Archived

This topic is now archived and is closed to further replies.

PepsiPlease

How to track object coordinates?

Recommended Posts

PepsiPlease    122
Hey, I am trying to write a very small game using OpenGL, but I don''t understand even the basics of collision detection. I have read through NeHe''s tutorial a few times, but I realize that code with such complexity is not needed in my case. All I have is a polygon that moves around a small map (the map made from an array following to article on this site). What I want is when the polygon goes into a wall (a 1 stored in the array), the object to stop. But I am not sure how to store the objects position in order to check for the collision. The map array looks like this: char map[10][10]{ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; {1, 2, 1, 0, 0, 0, 1, 0, 0, 1}; {1, 0, 1, 1, etc. etc. etc. All I have for the polygon is a square, starting from the position 2 on the array. Any help would be appreciated. Thanks

Share this post


Link to post
Share on other sites
invective    118
I am going to assume your square is less than or equal to one grid cell on your map.

1)You save the old position.
2)Update your position.
3)Check if the new position is valid.
*convert the four corners into integers (this tells you what
cell each corner is in).
*if the value of any cell containg a corner is a wall, the
new position is not valid.
4)If the new position was not valid, restore the old position.


  
class Object {

float top, left, bottom, right;
float oldTop, oldLeft, oldBottom, OldRight;
Map *map;

void savePosition {
oldTop = top; oldBottom = bottom;
oldLeft = left; oldRight = right;
}
void restorPosition {
top = oldTop; bottom = oldBottom;
left = oldLeft; right = oldRight;
}
bool updatePosition (int xAmount, int yAmount){
savePosition ();
top += yAmount;
bottom += yAmount;
left += xAmount;
right += xAmount;
if ((map->isWall (static_cast<int> (left),static_cast<int> (top)) ||
(map->isWall (static_cast<int> (right),static_cast<int> (top)) ||
(map->isWall (static_cast<int> (left),static_cast<int> (bottom)) ||
(map->isWall (static_cast<int> (right),static_cast<int> (bottom)) )
{
restorePosition ();
return false;
}
return true;
}
}


obviously you can optimize it for speed (although for a small 2d game I doubt you need to)

}


    

Share this post


Link to post
Share on other sites
PepsiPlease    122
Ok, I kind of understand, but a few things remain unclear to me.

First of all, how di I declare that a wall is a wall without declaring the whole map as being a wall. Also, whereabouts do I put this class and then call it from?

Thanks

Share this post


Link to post
Share on other sites
Peon    276
Not sure if this helps at all, but back when I was programming a QB RPG, I had it check to see if a tile was over a certain value. In my case, I reserved tiles from 0-100 as walkable tiles, and any thing else was impassable. Each time a character moved, I calculated if the square they wanted to move to was walkable or not.

Share this post


Link to post
Share on other sites
PepsiPlease    122
Well, then, would this work?

int ballpos;
int newballpos;
int x, y;
ballpos = map[x][y];
newballpos = map[x+1][y];
if (newballpos==2)
{
newballpos = ballpos;
}
xx+=1.0f;


EDIT: I changed the code a bit.


[edited by - PepsiPlease on June 7, 2002 4:43:21 PM]

Share this post


Link to post
Share on other sites
Jason Zelos    211

int BallX, BallY;
char Map[10][10]; //fill in blah


to move right:

if (BallX+Speed<=10) && (map[(BallX+Speed)][BallY]==0) BallX+=Speed;

to move left:

if (BallX-Speed>=0) && (map[(BallX-Speed)][BallY]==0) BallX-=Speed;


etc....

You might want to precache the (BallX/BallY +/- Speed). Bear in mind this is moving by tile, not neccesarly very smooth animation.

Also this only checks the one tile, if your square is bigger than a tile use invective''s method of checking all possible tiles covered.

,Jay

Share this post


Link to post
Share on other sites
invective    118
A few points of clarification:
1) The map has information about what kind of tile is located at a given cell. How you want to interpret this as solid or not is entirely up to you. You can flag only cells with a value of 0 as soild, those greater than 100, or those with the left most bit set, etc.. It doesn''t matter how you do it; its arbitary as long as you are consistant. Assume cells over 100 are "walls" or things you can''t walk on. For example, 100 could be a stone wall, 101 impassable water, 102 lava, etc. Doesn''t matter, as long as everything you can''t walk on is over 100.

//This function returns true if the square is greater than 100
bool map::isSolid (int x, int y)
{
//Its good practice to check array bounds in debug mode
assert ((x>0) && (x < MAP_WIDTH) && (y>0) && (y < MAP_HIEGHT));
return map[x][y] > 100;
}


2) You need to convert from world space into tile space. That is, if you have a 10x10 tile map, all tiles will fall on integer boundaries 0,1,2,3...9. You want your player/object/enemies to be able to smoothly walk between tiles, instead of jumping from tile to tile. This is why I suggested using floats. Then an object can be inbetween tiles, or standing on more than one tile. In fact if the object is less than or equal in size to a tile, it can be standing of at most 4 tiles at once (ie the 4 center corners are right under the center of the object), which is why you need to check all its corners. Larger objects can span even more than 4 tiles. Play with this on graph paper to make sure you understand.

Example:
Object X spans 4 tiles: [1,0] [2,0] [1,1] [2,1]

0 1 2
----------
| | | | 0
| | X|X |
----------
| | X|X | 1
| | | |
----------
| | | | 2
| | | |
----------

Share this post


Link to post
Share on other sites
PepsiPlease    122
invective: I understand about the object being able to be on 4 tiles at once, and I understand about using floats. (In fact, what I am doing currently is having the square move 0.02 tiles each frame.) But what I don''t understand is how to get the coordinates of the four corners in the first place. How do you return each coordinate so that you can check if it is in fact colliding with a wall?

Share this post


Link to post
Share on other sites
invective    118
This program uses glut / openGL; I hope you know how to compile it. If not I can send you the EXE.

I warn you it is VERY sloppy and stylistically very bad (globals and classes everywhere), but it works. 1/2 hour coding.

You can move the red "player" on the green "grass" but not the blue "water."


  
#include <cstdlib>
#include <GL/glut.h>

const int MAP_WIDTH = 10;
const int MAP_HIEGHT = 10;

class Map {
private:
int map [MAP_WIDTH][MAP_HIEGHT];
public:
Map () {
for (int x = 0; x < MAP_WIDTH; ++x)
for (int y = 0; y < MAP_HIEGHT; ++y)
{
if ((x==0) || (y==0) ||(x==(MAP_WIDTH-1))|| (y == (MAP_HIEGHT-1)))
map[x][y] = 0;
else
map [x][y] = (rand() % 7) ? 1 : 0;
}
map[1][1] = 1;
}
bool isSolid (float x, float y)
{
if ((x<0)||(y<0)||(x>=MAP_WIDTH)|| (y >=MAP_HIEGHT))
return true;
return map [static_cast<int>(x)] [static_cast<int>(y)] == 0;
}
void render ()
{
glBegin (GL_QUADS);
for (int x = 0; x < MAP_WIDTH; ++x)
for (int y = 0; y < MAP_HIEGHT; ++y)
{
if (map[x][y] == 0)
glColor3f (0,0,1);
else
glColor3f (0,1,0);
glVertex2f (x,y);
glVertex2f (x,y+1);
glVertex2f (x+1,y+1);
glVertex2f (x+1,y);
}
glEnd ();
}
};

class Player {
private:
Map *map;
float top, left, bottom, right;
float oldTop, oldLeft, oldBottom, oldRight;
void savePosition () {
oldTop = top; oldBottom = bottom;
oldLeft = left; oldRight = right;
}
void restorePosition () {
top = oldTop; bottom = oldBottom;
left = oldLeft; right = oldRight;
}
public:
Player (Map *m) : map (m) {
top = 1;
left = 1;
bottom = top + .8;
right = left + .5;
}
bool moveBy (float xAmount, float yAmount){
savePosition ();
top += yAmount;
bottom += yAmount;
left += xAmount;
right += xAmount;
if ((map->isSolid (left,top)) ||
(map->isSolid (right,top)) ||
(map->isSolid (left,bottom)) ||
(map->isSolid (right,bottom)))
{
restorePosition ();
return false;
}
return true;
}
void render () {
glBegin (GL_QUADS);
glColor3f (1,0,0);
glVertex2f (left,top);
glVertex2f (left,bottom);
glVertex2f (right,bottom);
glVertex2f (right,top);
glEnd ();
}
};


int window;
Map map;
Player player (&map);

void onSpecialKey(int key, int x, int y)
{
switch(key){
case GLUT_KEY_UP:
player.moveBy (0, -.05);
break;
case GLUT_KEY_DOWN:
player.moveBy (0, .05);
break;
case GLUT_KEY_RIGHT:
player.moveBy (.05, 0);
break;
case GLUT_KEY_LEFT:
player.moveBy (-.05, 0);
break;
}
glutPostRedisplay();
}

void onDisplay(void)
{

glutSetWindow(window);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
player.render ();
map.render ();
glutSwapBuffers();

}

void initDisplay()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D (0,10, 10, 0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glClearColor(0, 0, 0, 1);
glClearDepth(1);
}


int main(int argc, char **argv)
{

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

glutInitWindowSize(640,640);
window = glutCreateWindow("Tiles");
glutSpecialFunc(onSpecialKey);
glutDisplayFunc(onDisplay);
initDisplay();

glutMainLoop();
return 0;
}


Share this post


Link to post
Share on other sites
PepsiPlease    122
Well, I can see how that would work, but it won''t compile. Here''s the code for my classes:


  class map {
private:
int map[MAP_SIZEX][MAP_SIZEY];
public:
map() {
for (int x = 0; x < MAP_SIZEX; x++)
{
for (int y = 0; y < MAP_SIZEY; y++)
{
if ((x==0)||(y==0)||(x < MAP_SIZEX - 1)||(y < MAP_SIZEY - 1))
{
map[x][y] = 0;
}
else
{
map[x][y] = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 2, 1, 0, 0, 1, 0, 0, 0, 1},
{1, 0, 0, 0, 1, 1, 0, 1, 0, 1},
{1, 0, 1, 0, 0, 1, 0, 1, 1, 1},
{1, 0, 1, 1, 0, 1, 0, 0, 1, 1},
{1, 0, 1, 0, 0, 1, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
};
}
map[1][1] = 1;
}
}
bool isSolid(float x, float y)
{
if ((x<0)||(y<0)||(x>=MAP_WIDTH)|| (y >=MAP_HIEGHT))
{
return true;
}
return map [static_cast<int>(x)] [static_cast<int>(y)] == 0;
}
void render ()
{
draw_tiles();
draw_floor();
}
};
class Player
{
private:
Map *map;
float top, left, bottom, right;
float oldTop, oldLeft, oldBottom, oldRight;
void savePosition ()
{
oldTop = top; oldBottom = bottom;
oldLeft = left; oldRight = right;
}
void restorePosition ()
{
top = oldTop; bottom = oldBottom;
left = oldLeft; right = oldRight;
}
public:
Player (Map *m) : map (m)
{
top = 1;
left = 1;
bottom = top + .8;
right = left + .5;
}
bool moveBy (float xAmount, float yAmount)
{
savePosition ();
top += yAmount;
bottom += yAmount;
left += xAmount;
right += xAmount;
if ((map->isSolid (left,top)) ||
(map->isSolid (right,top)) ||
(map->isSolid (left,bottom)) ||
(map->isSolid (right,bottom)))
{
restorePosition();
return false;
}
return true;
}
void render()
{
draw_ball();
}
};

int window;
Map map;
Player player (&map);




But it just says there are problems with the code. Here is the compiler output.C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(51) : error C2380: type(s) preceding ''map'' (constructor with return type, or illegal redefinition of current class-name?)
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(51) : error C2059: syntax error : ''[''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(51) : error C2238: unexpected token(s) preceding '';''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(97) : error C2143: syntax error : missing '';'' before ''*''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(97) : error C2501: ''Map'' : missing storage-class or type specifiers
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(97) : error C2501: ''map'' : missing storage-class or type specifiers
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(111) : error C2629: unexpected ''class map:layer (''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(111) : error C2334: unexpected token(s) preceding '':''; skipping apparent function body
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(142) : error C2146: syntax error : missing '';'' before identifier ''map''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(142) : error C2501: ''Map'' : missing storage-class or type specifiers
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(142) : error C2208: ''class map'' : no members defined using this type
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(143) : error C2059: syntax error : ''&''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(616) : error C2535: ''long __stdcall map::WndProc(struct HWND__ *,unsigned int,unsigned int,long)'' : member function already defined or declared
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(146) : see declaration of ''WndProc''
C:\unzipped\basecode\Simple Basecode\Lesson1.cpp(792) : fatal error C1004: unexpected end of file found


All the errors seem to be coming from the map class, but I can''t figure out what is wrong.

Thanks

Share this post


Link to post
Share on other sites