Mouse interaction with a game map

Greetings everyone!

I’ve been wanting to write a simple strategy game, but I’ve been having an
issue with how to get a game map to work. Drawing it is very simple, but
keeping track of the mouse has become complicated.

I’ve always used something like:
if ((mousex >= areax) && (mousex <= areax + areaw))
to figure out if the mouse is in a certain region. But that only works for
square regions.

So what do I do for non-square areas?

An example of what I have in mind would be along the lines of Axis and Allies.
or Defender of the Crown.

The only idea I have is to use a type of bitmap to keep track of regions. But
that makes designing maps VERY complicated for me.

Anyone else have ideas?

Thanks in advance!

  • Micah

Micah Brening schrieb:

Greetings everyone!

I’ve been wanting to write a simple strategy game, but I’ve been having an
issue with how to get a game map to work. Drawing it is very simple, but
keeping track of the mouse has become complicated.

I’ve always used something like:
if ((mousex >= areax) && (mousex <= areax + areaw))
to figure out if the mouse is in a certain region. But that only works for
square regions.

So what do I do for non-square areas?

An example of what I have in mind would be along the lines of Axis and Allies.
or Defender of the Crown.

The only idea I have is to use a type of bitmap to keep track of regions. But
that makes designing maps VERY complicated for me.

Anyone else have ideas?

I think this is what you want:
http://www.gamedev.net/reference/articles/article421.asp
or this:
http://www.gamedev.net/reference/articles/article422.asp

You have a polygon defining the region and you want to check if a point

  • your mouse cursor - is in this region.

Regards,
Janosch Gr?f

Janosch Gr?f <janosch.graef gmx.net> writes:

I think this is what you want:
http://www.gamedev.net/reference/articles/article421.asp
or this:
http://www.gamedev.net/reference/articles/article422.asp

You have a polygon defining the region and you want to check if a point

  • your mouse cursor - is in this region.

Regards,
Janosch Gr?f

These algorithims are a bit deep so I’ll have to study them a bit. However, it
looks like it was what I was looking for!

So a map editor would need to kick out a collection of vertexes for each region
to define the polygon rather than a bitmapped map.

That makes sense. Thanks for the help!

If your game is using 2d art (vs. 3d models) then you can also use a mask
for each map tile and just test against the mask. This can be much simpler
to do; at least for 2d tile based games.> ----- Original Message -----

From: sdl-bounces@lists.libsdl.org [mailto:sdl-bounces at lists.libsdl.org] On
Behalf Of Micah Brening
Sent: Thursday, July 23, 2009 12:05 PM
To: sdl at libsdl.org
Subject: Re: [SDL] Mouse interaction with a game map

Janosch Gr?f <janosch.graef gmx.net> writes:

I think this is what you want:
http://www.gamedev.net/reference/articles/article421.asp
or this:
http://www.gamedev.net/reference/articles/article422.asp

You have a polygon defining the region and you want to check if a point

  • your mouse cursor - is in this region.

Regards,
Janosch Gr?f

These algorithims are a bit deep so I’ll have to study them a bit. However,
it
looks like it was what I was looking for!

So a map editor would need to kick out a collection of vertexes for each
region
to define the polygon rather than a bitmapped map.

That makes sense. Thanks for the help!


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Ken Rogoway <Ken HomebrewSoftware.com> writes:

If your game is using 2d art (vs. 3d models) then you can also use a mask
for each map tile and just test against the mask. This can be much simpler
to do; at least for 2d tile based games.

I was just able to test the functions (good ol’ copy and paste) Well… It
didn’t work. I had to change it to:
pointinpoly(point pt,int cnt,point *polypts)
{
int i = 0;
while (i < cnt) {
if ((polypts[i].x == pt.x) && (polypts[i].y == pt.y)) {
return 1;
}
i++;
}
return 0;
}
That’s VERY ineficciant. But it worked. The other one returned a non-zero at
random.

The game may be tile based, however, I need the regions, countries, shires,
areas, whatever to not be squares or rectangles.

And yes, it would be 2d.

2009/7/23 Ken Rogoway

If your game is using 2d art (vs. 3d models) then you can also use a mask
for each map tile and just test against the mask. This can be much simpler
to do; at least for 2d tile based games.

Like this:

int pointalpha(SDL_Surface* surface, int x, int y)

Let’s try that again…

2009/7/23 Ken Rogoway

If your game is using 2d art (vs. 3d models) then you can also use a mask

for each map tile and just test against the mask. ?This can be much simpler
to do; at least for 2d tile based games.

Like this:

bool pointontile(SDL_Surface* surface, int x, int y) {
Uint8* ptr = (Uint8*) surface->pixels + y * surface->pitch + x *
surface->format->BytesPerPixel;
return (((Uint32) ptr) & surface->format->Amask) != 0;
}


/* figure out what tile you’re over… /
/
for tiles in this order: below and right, below, below and left,
right, and at position… / {
if (pointontile(tile.image, mousex-tile.x, mousey-tile.y)) {
/
do stuff… */
break;
}
}

If all your tiles are the same size and don’t overlap though, then
this would be pretty wasteful.
Either way, you need to figure out what tile you’re over.

Let’s say you have a 32x32 square tile. Square tiles are pretty easy…

#define TILEWIDTH 32
#define TILEHEIGHT 32

void gettilepos(int pixelx, int pixely, int& tilex, int& tiley) {
tilex = pixelx / TILEWIDTH;
tiley = pixely / TILEHEIGHT;
}

Let’s say you have a 64x32 diamond shaped tile. Tiles in a row are
spaced 64 pixels apart. The second row is offset by 32x16 from the
first. The third row is offset by -32x16 from the second and 0x64
from the first. If this seems familiar, you’ve probably been playing
Furcadia.

#define TILEWIDTH 64
#define TILEHEIGHT 32

void gettilepos(int pixelx, int pixely, int& tilex, int& tiley) {
int divx = pixelx / TILEWIDTH, modx = (pixelx % TILEWIDTH);
int divy = pixely / TILEHEIGHT, mody = (pixely % TILEHEIGHT);

tilex = divx;
tiley = divy*2;

if (mody * 2 < TILEHEIGHT)	{
	if ((modx+1) * 2 * TILEHEIGHT < (TILEHEIGHT - mody*2) * TILEWIDTH)	{
		--tilex;
		--tiley;
	}
	if (((modx-1) * 2 - TILEWIDTH) * TILEHEIGHT >= mody*2 * TILEWIDTH)	{
		--tiley;
	}
} else	{
	if ((modx+1) * 2 * TILEHEIGHT < ((mody+1) * 2 - TILEHEIGHT) * TILEWIDTH)	{
		--tilex;
		++tiley;
	}
	if (((modx-1) * 2 - TILEWIDTH) * TILEHEIGHT >= (TILEHEIGHT -

(mody+1))*TILEWIDTH * 2) {
++tiley;
}
}
}

Now let’s say you have a Wesnoth style hex tile. The top and bottom
of the hexagon are both 36 pixels. The sides are at a 1:2 angle and
are 18x36 pixels. The bounding box for each tile is 72x72 pixels.
Tiles in a row are spaced 108 pixels apart. The second row is offset
by 54x36 pixels from the first row. The third row is offset by -54x36
pixels from the second and 0x72 pixels from the first.

#define FLATSWIDTH 36
#define SIDEWIDTH 18
#define SIDEHEIGHT 36

#define TILEWIDTH (FLATSWIDTH+2SIDEWIDTH)
#define TILEHEIGHT (2
SIDEHEIGHT)
#define ROWSPACING (2*(FLATSWIDTH+SIDEWIDTH))

void gettilepos(int pixelx, int pixely, int& tilex, int& tiley) {
int divx = pixelx / ROWSPACING, modx = pixelx % ROWSPACING;
int divy = pixely / TILEHEIGHT, mody = pixely % TILEHEIGHT;

tilex = divx;
tiley = divy * 2;
if (mody < SIDEHEIGHT) {
	if (modx < SIDEWIDTH) {
		if (modx * SIDEHEIGHT < (SIDEHEIGHT - mody) * SIDEWIDTH) {
			--tilex;
			--tiley;
		}
	} else {
		modx -= SIDEWIDTH + FLATSWIDTH;
		if (modx >= 0 && (modx >= SIDEWIDTH || modx * SIDEHEIGHT >= mody *

SIDEWIDTH))
–tiley;
}
} else {
mody -= SIDEHEIGHT;
if (modx < SIDEWIDTH) {
if (modx * SIDEHEIGHT < mody * SIDEWIDTH) {
–tilex;
++tiley;
}
} else {
modx -= SIDEWIDTH + FLATSWIDTH;
if (modx >= 0 && (modx >= SIDEWIDTH || modx * SIDEHEIGHT >=
(SIDEHEIGHT - mody) * SIDEWIDTH))
++tiley;
}
}
}

(this one acts funny when passed negative values, so don’t do that)

There’s a test program for these functions attached.
-------------- next part --------------
A non-text attachment was scrubbed…
Name: test.cpp
Type: text/x-c++src
Size: 4223 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20090724/5507bd8b/attachment.cpp

2009/7/24 Kenneth Bull <@Kenneth_Bull>:

Now let’s say you have a Wesnoth style hex tile. ?The top and bottom
of the hexagon are both 36 pixels. ?The sides are at a 1:2 angle and
are 18x36 pixels. ?The bounding box for each tile is 72x72 pixels.
Tiles in a row are spaced 108 pixels apart. ?The second row is offset
by 54x36 pixels from the first row. ?The third row is offset by -54x36
pixels from the second and 0x72 pixels from the first.

correction: missing a - 1

#define FLATSWIDTH 36
#define SIDEWIDTH 18
#define SIDEHEIGHT 36

#define TILEWIDTH (FLATSWIDTH+2SIDEWIDTH)
#define TILEHEIGHT (2
SIDEHEIGHT)
#define ROWSPACING (2*(FLATSWIDTH+SIDEWIDTH))

void gettilepos(int pixelx, int pixely, int& tilex, int& tiley) {
int divx = pixelx / ROWSPACING, modx = pixelx % ROWSPACING;
int divy = pixely / TILEHEIGHT, mody = pixely % TILEHEIGHT;

tilex = divx;
tiley = divy * 2;
if (mody < SIDEHEIGHT) {
	if (modx < SIDEWIDTH) {
		if (modx * SIDEHEIGHT < (SIDEHEIGHT - mody - 1) * SIDEWIDTH) {
			--tilex;
			--tiley;
		}
	} else {
		modx -= SIDEWIDTH + FLATSWIDTH;
		if (modx >= 0 && (modx >= SIDEWIDTH || modx * SIDEHEIGHT >= mody *

SIDEWIDTH))
–tiley;
}
} else {
mody -= SIDEHEIGHT;
if (modx < SIDEWIDTH) {
if (modx * SIDEHEIGHT < mody * SIDEWIDTH) {
–tilex;
++tiley;
}
} else {
modx -= SIDEWIDTH + FLATSWIDTH;
if (modx >= 0 && (modx >= SIDEWIDTH || modx * SIDEHEIGHT >=
(SIDEHEIGHT - mody - 1) * SIDEWIDTH))
++tiley;
}
}
}

revised test program attached
-------------- next part --------------
A non-text attachment was scrubbed…
Name: test.cpp
Type: text/x-c++src
Size: 4231 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20090724/2ca94c83/attachment.cpp

Kenneth Bull <llubnek gmail.com> writes:

2009/7/24 Kenneth Bull <llubnek gmail.com>:

Now let’s say you have a Wesnoth style hex tile. ?The top and bottom
of the hexagon are both 36 pixels. ?The sides are at a 1:2 angle and
are 18x36 pixels. ?The bounding box for each tile is 72x72 pixels.
Tiles in a row are spaced 108 pixels apart. ?The second row is offset
by 54x36 pixels from the first row. ?The third row is offset by -54x36
pixels from the second and 0x72 pixels from the first.

Kenneth,
I really appreciate your help.
However, I’m not certain I’m explaining myself
correctly.

Interacting with tiles isn’t the issue I have.

Say I have a game map similar to:
http://coldones.eu/images/maps/westeros_political.gif
The borders do not form a perfect rectangle.

So if I were to have a user move their mouse over the
country or whatnot they
wish to select,
how can I tell what country they are over?

Options I can figure is have a bitmap
mask with a color per country they can select.

The second option is an array of vertexes which would list pixels per region.

The second seems costly. And the first seems redundant.

Both options are costly, but they cost different things. Using a
matrix (bitmap) is effectively just shipping your game with pre-cached
calculations of which region(s) each pixel represents. This costs
memory. Not caching costs less memory, and a little more CPU.

While it’s certainly comparing apples to oranges, I like to tell
people that memory is much more precious these days than CPU is.

If you’re tickled by hackishness as I am, you might consider using the
actual graphical pixel values to determine what the mouse is hovering
over. If you cram a region code into the lower 2 bits of three color
channels, you can represent 64 different regions, and most players
won’t notice the effect it has on your artwork :stuck_out_tongue: :stuck_out_tongue: :POn Sat, Jul 25, 2009 at 1:18 PM, Micah Brening<micah.brening at gmail.com> wrote:

So if I were to have a user move their mouse over the
country or whatnot they
wish to select,
how can I tell what country they are over?

Options I can figure is have a bitmap
mask with a color per country they can select.

The second option is an array of vertexes which would list pixels per region.

The second seems costly. ?And the first seems redundant.


http://codebad.com/

That’s dirty! :slight_smile:

Jonny DOn Sat, Jul 25, 2009 at 4:11 PM, Donny Viszneki<donny.viszneki at gmail.com> wrote:

If you’re tickled by hackishness as I am, you might consider using the
actual graphical pixel values to determine what the mouse is hovering
over. If you cram a region code into the lower 2 bits of three color
channels, you can represent 64 different regions, and most players
won’t notice the effect it has on your artwork :stuck_out_tongue: :stuck_out_tongue: :stuck_out_tongue:

Both options are costly, but they cost different things. Using a
matrix (bitmap) is effectively just shipping your game with pre-cached
calculations of which region(s) each pixel represents. This costs
memory. Not caching costs less memory, and a little more CPU.

While it’s certainly comparing apples to oranges, I like to tell
people that memory is much more precious these days than CPU is.

If you’re tickled by hackishness as I am, you might consider using the
actual graphical pixel values to determine what the mouse is hovering
over. If you cram a region code into the lower 2 bits of three color
channels, you can represent 64 different regions, and most players
won’t notice the effect it has on your artwork :stuck_out_tongue: :stuck_out_tongue: :stuck_out_tongue:

Donny,

That’s a clever idea.

Please don’t take my comments as argumentative in any way, but unless you
are on a very tight platform memory wise, it is actually pretty effective
to use a mask for each tile. The reason this is true is that you can cram
your masks into width/8*height bytes of data since you only need to use 1
bit per pixel.

  • Ken Rogoway

My suggestion was not meant to be taken very seriously.

I don’t think what you’re saying is true, though. OP is not using
tiles in his game. (Did you mean pixels?) OP also doesn’t need 1 bit
per pixel.

The truth is that the runtime resource consumption isn’t big enough to
matter. OP should make the decision based on which method he or she
thinks will be easiest to implement, both in terms of the game program
and in terms of creating game content.On Sat, Jul 25, 2009 at 10:09 PM, Ken Rogoway wrote:

Please don’t take my comments as argumentative in any way, but unless you
are on a very tight platform memory wise, it is actually pretty effective
to use a mask for each tile. ?The reason this is true is that you can cram
your masks into width/8*height bytes of data since you only need to use 1
bit per pixel.


http://codebad.com/

Micah, actually, here is another option to consider: just create a
rectangular box oriented at the angle of the screen just around the
name of each region. IMHO, it might actually be better this way, since
the player won’t be tempted to click near the boundary between two
territories, and perhaps miss the mark. The collision detection for
this is dirt simple, and I think it already exists in SDL.–
http://codebad.com/

My suggestion was not meant to be taken very seriously.
:slight_smile:

I don’t think what you’re saying is true, though. OP is not using
tiles in his game. (Did you mean pixels?) OP also doesn’t need 1 bit
per pixel.
I use tiles to mean any n x m 2d surface. These are typically used in
scrolling games, and isometric map based games. I must have misunderstood
his original post as I thought that was the type of game he was doing.

The truth is that the runtime resource consumption isn’t big enough to
matter. OP should make the decision based on which method he or she
thinks will be easiest to implement, both in terms of the game program
and in terms of creating game content.
I totally agree