Jump to content

  • Log In with Google      Sign In   
  • Create Account

Collision Handling Irregular Objects 2d RPG


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
3 replies to this topic

#1 BwetArrow   Members   -  Reputation: 122

Like
0Likes
Like

Posted 27 January 2012 - 12:34 PM

[EDIT: This topic is probably better for the "For Beginner's" Forum, I wouldn't mind if it were moved.

Hey,

I have been searching for ages for decent collision detection on irregular objects with 8-directional movement in a 2d game where the level is moved and the character stays centered. The game is in Actionscript 3, but this is a general question about logic, not implementation.

What I have so far is buggy to the extreme, and I can't find anything online to suit my needs.

This is what I have so far(see end for summary):

[in the Main.as document class]:
1)Function to detect collision and act accordingly, which is done 24 times/second
public function collisionsCheck(evt:Event):void
  {
   var collisions:Array = collisionList.checkCollisions(); //puts colliding objects into an array
   if (collisions.length == 0)//if no collisions
   {
	moveAvatar();
   }
   else
   {
	for (var i:uint = 0; i < collisions.length; i++)
	{
	 if (collisions[i].object2 is levelWall)
	 {
	  bounceAvatar();
	 }
	 else
	 {
	  moveAvatar();
	 }
	}
   }
  }

2)moveAvatar() function:
public function moveAvatar():void
  {
   xMovement = 0;
   yMovement = 0;
   currentDirection = "";
   if (rightArrow == true && upArrow == false && downArrow == false)
   {
	xMovement -=  charSpeed; //sets speed
   }
   else if (leftArrow == true && upArrow == false && downArrow == false)
   {
	xMovement +=  charSpeed;
   }
//etc for all 8 directions
						ourLevel.x +=  xMovement; //moves level according to speed
   ourLevel.y +=  yMovement;
  }

3)bounceAvatar() function:
public function bounceAvatar():void
  {
   if (currentDirection == "")
   {
	if (leftArrow == true && upArrow == false && downArrow == false)
	{
	 ourLevel.x--;
	 currentDirection = "Left";
	}else if (rightArrow == true  && upArrow == false && downArrow == false)
	{
	 ourLevel.x++;
	 currentDirection = "Right";
	}
//etc for all directions
   }
   else
   {
	if (currentDirection == "Left")
	{
	 ourLevel.x--;
	}
	else if (currentDirection == "Right")
	{
	 ourLevel.x++;
	}
   }
  }
//etc for all directions

So in summary, i put the colliding objects in an array, then if that array is longer than 0, i check to see if it is a wall, and if it is, i call the bounceAvatar function, which checks the direction(if it's "empty", from the moveAvatar, it sets it), and moves the level until the array length is 0 again. If it is not a wall, or the length is 0, I move the level according to the direction and speed of the character.

Now obviously on irregular objects, and probably on regular objects too, this collision handling is primitive and buggy, because it sometimes moves the character through walls if it changes directions the right way.

Does anyone know how I could improve this? Or could you point me in the right direction? Remember, I just need the logic, code is not necessary. I have tried variations of this that have the same problem, and the frustration is reaching critical levels x.x, so any fresh ideas are welcome!

Thank you a LOT for your time, I know how valuable it is!
There is no cure for birth and death, save to enjoy the interval. xD

Sponsor:

#2 ProvenDantheman   Members   -  Reputation: 111

Like
1Likes
Like

Posted 27 January 2012 - 01:09 PM

Use Separate Axis Theorem
My implementation:

class vert{
public:
float x,y;
~vert();
vert();
vert(float,float);
vert &vert::operator=(vert);
vert normal();
};
vert::~vert(){
}
vert::vert(){
x = y = 0;
}
vert::vert(float initx, float inity){
x = initx;
y = inity;
}
vert  &vert::operator=(vert initp){
x = initp.x;
y = initp.y;
return(*this);
}
vert vert::normal(){
vert norm = *this;
float mag = sqrt((norm.x * norm.x) + (norm.y * norm.y));
norm.x /= mag;
norm.y /= mag;
return(norm);
}
class poly{
vert projection(vert);
public:
int vert_count;
vert * verts;
vert center;
vert mtv;
poly(int,...);
poly();
~poly();
poly &poly::operator = (poly);
void collision(poly*,bool);
bool collided;
float density;
};
poly::poly(int N,...){
density = 1;
verts = new vert[N];
vert_count = N;
va_list list;
va_start(list,N);
for(int i = 0; i < N; i++){
  verts[i] = va_arg(list,vert);
}
va_end(list);
center = vert(0,0);
for(int i = 0; i < N; i++){
  center.x += verts[i].x;
  center.y += verts[i].y;
}
center.x /= N;
center.y /= N;
}
poly::poly(){
vert_count = 0;
density = 1;
}
poly::~poly(){
}
poly &poly::operator=(poly apoly){
if(vert_count > 0){
  delete[]verts;
}
vert_count = apoly.vert_count;
verts = new vert[vert_count];
for(int i = 0; i < vert_count; i++){
  verts[i] = apoly.verts[i];
}
center = apoly.center;
return(*this);
}
vert poly::projection(vert axis){
float min = (axis.x * verts[0].x) + (axis.y * verts[0].y);
float max = min;
for(int i = 0; i < vert_count; i++){
  float pro = (axis.x * verts[i].x) + (axis.y * verts[i].y);
  if(pro < min){
   min = pro;
  }
  if(pro > max){
   max = pro;
  }
}
return(vert(min,max));
}
void poly::collision(poly* tpoly,bool both = false){
vert * edges = new vert[vert_count];
vert * edges2 = new vert[tpoly->vert_count];
collided = true;
for(int i = 0; i < vert_count; i++){
  vert a = verts[i];
  vert b = verts[i+1 == vert_count ? 0 : i+1];
  edges[i] = vert(b.x - a.x, b.y - a.y);
  edges[i] = edges[i].normal();
}
for(int i = 0; i < tpoly->vert_count; i++){
  vert a = tpoly->verts[i];
  vert b = tpoly->verts[i+1 == tpoly->vert_count ? 0 : i+1];
  edges2[i] = vert(b.x - a.x, b.y - a.y);
  edges2[i] = edges2[i].normal();
}
float overlap = 9999;
vert smallest;
for(int i = 0; i < vert_count; i++){
  vert p1 = projection(edges[i]);
  vert p2 = tpoly->projection(edges[i]);
  if(p1.y >= p2.x && p2.y >= p1.x){
   float toverlap;
   if(p1.x <= p2.x){
    toverlap = p1.y - p2.x;
   }
   else{
    toverlap = p2.y - p1.x;
   }
   if(toverlap < overlap){
    overlap = toverlap;
    smallest = edges[i];
   }
  }
  else{
   collided = false;
  }
}
for(int i = 0; i < tpoly->vert_count; i++){
  vert p1 = projection(edges2[i]);
  vert p2 = tpoly->projection(edges2[i]);
  if(p1.y >= p2.x && p2.y >= p1.x){
   float toverlap;
   if(p1.x <= p2.x){
    toverlap = p1.y - p2.x;
   }
   else{
    toverlap = p2.y - p1.x;
   }
   if(toverlap < overlap){
    overlap = toverlap;
    smallest = edges2[i];
   }
  }
  else{
   collided = false;
  }
}
if(collided){
  vert dist = vert(tpoly->center.x - center.x, tpoly->center.y - center.y);
  float check;
  check = dist.x * smallest.x + dist.y * smallest.y;
  if(check < 0){
   smallest.x *= -1;
   smallest.y *= -1;
  }
  if(!both){
   for(int i = 0; i < vert_count; i++){
    verts[i].x -= smallest.x*overlap;
    verts[i].y -= smallest.y*overlap;
   }
   mtv.x = -smallest.x*overlap;
   mtv.y = -smallest.y*overlap;
  }
  else{
   float m1 = density, m2 = tpoly->density;
   float normp = sqrt((density+tpoly->density)*(density+tpoly->density));
   m1 /= normp;
   m2 /= normp;
   for(int i = 0; i < vert_count; i++){
    verts[i].x -= (smallest.x*overlap)*m1;
    verts[i].y -= (smallest.y*overlap)*m1;
   }
   for(int i = 0; i < tpoly->vert_count; i++){
    tpoly->verts[i].x += (smallest.x*overlap)*m2;
    tpoly->verts[i].y += (smallest.y*overlap)*m2;
   }
   mtv.x = -smallest.x*overlap*m1;
   mtv.y = -smallest.y*overlap*m1;
   tpoly->mtv.x = smallest.x*overlap*m2;
   tpoly->mtv.y = smallest.y*overlap*m2;
  }
  center = vert(0,0);
  for(int i = 0; i < vert_count; i++){
   center.x += verts[i].x;
   center.y += verts[i].y;
  }
  center.x /= vert_count;
  center.y /= vert_count;
  tpoly->center = vert(0,0);
  for(int i = 0; i < tpoly->vert_count; i++){
   tpoly->center.x += tpoly->verts[i].x;
   tpoly->center.y += tpoly->verts[i].y;
  }
  tpoly->center.x /= tpoly->vert_count;
  tpoly->center.y /= tpoly->vert_count;
}
delete[]edges;
delete[]edges2;
}


#3 BwetArrow   Members   -  Reputation: 122

Like
0Likes
Like

Posted 27 January 2012 - 04:48 PM

Thank you!

Just to make sure, I am inching my way through this, but is separate axis theorem not for collision handling, but detection? Please tell me if I am wrong, I am not too far in yet.
There is no cure for birth and death, save to enjoy the interval. xD

#4 ProvenDantheman   Members   -  Reputation: 111

Like
0Likes
Like

Posted 27 January 2012 - 05:47 PM

It's for both




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS