Image Collison for Unknown Curves

Member
Posts: 78
Joined: 2004.06
Post: #1
I just started working on the 'terrain' section of my 2d-sidescrolling platformer; and have run into a bit of a problem.
I'm using collison detection between a character's image and the terrain image, which has an unkown curve. I can get the character to land and walk around on a flat surfece, but I have NO idea how I would do//test this with unkown curved terrain objects. Any Suggestions?

Thanks

When in doubt ... read the Read Me
10.5.6 | MacBook Pro 2.5x2 | 4 GB RAM | GeForce 8600M GT
Quote this message in a reply
Moderator
Posts: 1,140
Joined: 2005.07
Post: #2
If you have an array of points, you could test the y coordinate of the terrain for the x coordinate of the player to the y coordinate of the player. If the y coordinate of the player is <= the y coordinate of the terrain, you've collided. If you don't have such an array, it could be useful to create one.
Quote this message in a reply
Member
Posts: 78
Joined: 2004.06
Post: #3
Wow that could be.... very complex. Is there any easier way?

When in doubt ... read the Read Me
10.5.6 | MacBook Pro 2.5x2 | 4 GB RAM | GeForce 8600M GT
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #4
What exactly do you mean by an "unknown" curve? Surely you know the shape of the terrain, how else would you draw it?

The two best ways to handle 2D terrain collisions in general is the way that akb825 said, or split your terrain into short line segments and collide your objects against those.

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Oldtimer
Posts: 832
Joined: 2002.09
Post: #5
So if I understand you correctly, you have arbitrary images of the terrain that you need to walk around on? In that case, you need to analyze the alpha mask of those images and decide that you can only walk on pixels that have an alpha of 100% or something like it.

However, this is not practical. I'd go with Skorche's suggestion of line segments. If you check out El Ballo in my signature, I used separate polylines for collision detection, and drew arbitrary images in the viewport.
Quote this message in a reply
Nibbie
Posts: 1
Joined: 2010.11
Post: #6
I happen to have just the code for you. Unfortunately it's in Java, but you should be able to get something working.

Code:
class sprite
{
  boolean[][] bitMask;
  PImage[] img=new PImage[16];
  float x,y;
  int w,h,ix,iy,bcs;
  float fps;
  int frames;
  float currentFramef=0;
  int currentFramei=0;
  boolean loop=true;
  boolean visable=true;
  int upper=0;
  int lower=0;
  
  sprite(String _img)
  {
    newSprite(_img,0,0,30);
  }
  sprite(String _img, float _x, float _y)
  {
    newSprite(_img,_x,_y,30);
  }
  sprite(String _img, float _x, float _y,float _fps)
  {
    newSprite(_img,_x,_y,_fps);
  }
  void newSprite(String _img, float _x, float _y, float _fps)
  {
    x=_x;
    y=_y;
    img[0]=loadImage(_img);
    bcs=int(sqrt(sq(img[0].width)+sq(img[0].height))/2);
    w=img[0].width;
    h=img[0].height;
    ix=int(x);
    iy=int(y);
    fps=_fps;
    frames=1;
    upper=frames;
    
    bitMask=new boolean[16][w*h];
    img[0].loadPixels();
    for(int j=0;j<h;j++){
      for(int i=0;i<w;i++){
          if(alpha(img[0].pixels[j*w+i])==255) bitMask[0][j*w+i]=true; }}
  }
  void addFrame(String _img)
  {
    if(frames==16){ println("Max Frames Exceeded"); return; }
    img[frames]=loadImage(_img);
    img[frames].loadPixels();
    for(int j=0;j<h;j++){
      for(int i=0;i<w;i++){
          if(alpha(img[frames].pixels[j*w+i])==255) bitMask[frames][j*w+i]=true; }}
    frames++;
    upper=frames;
  }
  void set(float _x, float _y)
  {
    x=_x;
    y=_y;
    ix=int(x);
    iy=int(y);
  }
  void move(float _x, float _y)
  {
    x+=_x;
    y+=_y;
    ix=int(x);
    iy=int(y);
  }
  boolean collides(sprite that)
  {
    if(sq(x-that.x)+sq(y-that.y)>sq(bcs+that.bcs)) return false;
    if (iy > that.iy+that.h) return false;
    if (iy+h < that.iy) return false;
    if (ix+w < that.ix) return false;
    if (ix > that.ix+that.w) return false;
    
    // Ok, compute the rectangle of overlap:
    int over_bottom,over_top,over_right,over_left;
    if (iy < that.iy) over_bottom = that.iy;
    else over_bottom = iy;

    if (iy+h > that.iy+that.h) over_top = that.iy+that.h;
    else over_top = iy+h;

    if (ix+w > that.ix+that.w) over_right = that.ix+that.w;
    else over_right = ix+w;

    if (ix < that.ix) over_left = that.ix;
    else over_left = ix;
    over_right-=over_left;
    over_top-=over_bottom;
    
    //fill(0,255,0,128);
    //rect(over_left,over_bottom,over_right,over_top);
    
    int thix, thiy, thax, thay;
    thix=over_left-ix;
    thiy=over_bottom-iy;
    
    thax=over_left-that.ix;
    thay=over_bottom-that.iy;
    
    /*for(int j=0;j<over_top;j++)
      for(int i=0;i<over_right;i++)
        if(bitMask[(j+thiy)*w+i+thix]) point(thix+ix+i,thiy+iy+j);*/
    for(int j=0;j<over_top;j++)
      for(int i=0;i<over_right;i++)
        if(bitMask[currentFramei][(j+thiy)*w+i+thix]&bitMask[that.currentFramei][(j+thay)*w+i+thax]) return true;
    
    return false;
  }
  void reset()
  {
    visable=true;
    currentFramef=0;
    currentFramei=0;
  }
  void cap(int _min,int _max)
  {
    lower=_min;
    upper=_max+1;
  }
  void setFrame(int _frm)
  {
    currentFramef=_frm;
    currentFramei=_frm;
  }
  void onlyFrame(int which)
  {
    currentFramef=which;
    currentFramei=which;
    lower=which;
    upper=which+1;
  }
  void draw()
  {
    int mn=max(0,lower);
    int mx=min(upper,frames);
    if(!visable) return;
    image(img[currentFramei], x, y);
    currentFramef+=(float)fps/(float)framerate;
    if(loop==true) currentFramef=mn+(currentFramef-mn)%(mx-mn);
    else if(currentFramef%frames>mx) visable=false;
    currentFramei=int(floor(currentFramef));
    
    //stroke(255,0,0);
    //noFill();
    //ellipse(x+img[currentFramei].width/2,y+img[currentFramei].height/2,bcs*2,bcs*2);
    //rect(ix,iy,w,h);
    /*for(int j=0;j<h;j++)
      for(int i=0;i<w;i++)
          if(bitMask[j*w+i]) point(ix+i,iy+j);*/
  }
}

The bit you're interested in is the function "boolean collides(sprite that)"
(ix,iy) is the position of the sprite (w,h) are the dimensions bcs is the bounding circle radius. bitMask[currentFrame][pixels] is a boolean collision map of the sprite created in newSprite from the alpha mask.

Ask if you have any questions.
Quote this message in a reply
Member
Posts: 78
Joined: 2004.06
Post: #7
Grin
Thanks Guys

Quote:What exactly do you mean by an "unknown" curve? Surely you know the shape of the terrain, how else would you draw it?

I actually don't know the curve, since I'm just drawing an picture to the screen and working with that picture.

I think splitting the terrain up might look a little bit too wierd for the stuff I'm trying to do, but it might just have to do if nothing else works.

Joseph I'll give your code a shot, it looks promising.

Thanks for the help guys! Wink

When in doubt ... read the Read Me
10.5.6 | MacBook Pro 2.5x2 | 4 GB RAM | GeForce 8600M GT
Quote this message in a reply
Oldtimer
Posts: 832
Joined: 2002.09
Post: #8
Shunter,
Take a look at what I'm doing in El Ballo.
http://www.elballo.com/postmortem/el_ballo_igda.pdf (Not sure about the page number, it's #2 of the Bad Stuff. There's an image of the editor where you can see the polylines overlaid on the graphics.)

I've been trying to find a better screenshot that shows off what I'm getting at, but I can't find them. :-/ The basic technique is, anyway, that you can have any graphic you want, and then just create arbitrary line strips for collision. Keep asking if you want more of a clarification. Smile
Quote this message in a reply
Member
Posts: 78
Joined: 2004.06
Post: #9
Yeah, OK, I get that. Its a good idea, but...

I'd like to be able to do it without having to manually work on each picture. I think I found out how to do it with shadow collisons steps. (ie testing for collison on either side of the characters and real-time configuring for the slope of the curves)

I'll keep you posted, thanks for the help.

When in doubt ... read the Read Me
10.5.6 | MacBook Pro 2.5x2 | 4 GB RAM | GeForce 8600M GT
Quote this message in a reply
Member
Posts: 78
Joined: 2004.06
Post: #10
Haha I found a better way. Grin

Its almost like your method Ivan, but instead of configuring each image manually, I wrote a function to simply peek through the alpha mask and find the first vertical appearance of a "ground spot", while loading the game. It then takes those coordinates and stores them in the object's array. Since I only have to take a vertical test every hundered pixels or so, it doesn't hinder the loading time much. Although I only have a few images now, nevermind a few hundered :/

When in doubt ... read the Read Me
10.5.6 | MacBook Pro 2.5x2 | 4 GB RAM | GeForce 8600M GT
Quote this message in a reply
Member
Posts: 78
Joined: 2004.06
Post: #11
Ok, so I got it up to where I saw in your editor, Ivan.
I have another question though, what's the best way to check for "collision" between the character and the line?
You don't want to make to big a gap, or he'll stay too far above it, and if it's too small, he might go through it.

When in doubt ... read the Read Me
10.5.6 | MacBook Pro 2.5x2 | 4 GB RAM | GeForce 8600M GT
Quote this message in a reply
Post Reply