Pages: 1 2 »
  Print  
Author Topic: move_contact functions optimised for bbox  (Read 22095 times)
Offline (Male) RetroX
Posted on: December 31, 2010, 12:09:58 am

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Code: [Select]
int move_contact(double direction, double max_distance, bool solid_only)
{
  enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  double max_x = lengthdir_x(direction, max_distance);
  double max_y = lengthdir_y(direction, max_distance);
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(all); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst2->id == inst1->id || solid_only && !inst2->solid) continue;
    if (max_x > 0)
    {
      const double x1 = inst1->x + max_x, x2 = inst2->x + inst2->bbox_left;
      if (x2 < x1)
      {
        max_x = x2 - inst1->x;
      }
    }
    else if (max_x < 0)
    {
      const double x1 = inst1->x + max_x, x2 = inst2->x + inst2->bbox_right;
      if (x2 > x1)
      {
        max_x = x2 - inst1->x;
      }
    }
   
    if (max_y > 0)
    {
      const double y1 = inst1->y + max_y, y2 = inst2->y + inst2->bbox_top;
      if (y2 < y1)
      {
        max_y = y2 - inst1->y;
      }
    }
    else if (max_y < 0)
    {
      const double y1 = inst1->y + max_y, y2 = inst2->y + inst2->bbox_bottom;
      if (y2 > y1)
      {
        max_y = y2 - inst1->y;
      }
    }
  }
  inst1->x += max_x;
  inst1->y += max_y;
 
  return 0;
}

inline int move_contact_solid(double direction, double speed) { return move_contact(direction, speed, true); }
inline int move_contact_all(double direction, double speed)   { return move_contact(direction, speed, false); }

Haven't tested it yet, but this should work.  Also am going under the assumption that objects don't collide when they share an edge.
« Last Edit: December 31, 2010, 12:15:24 am by RetroX » Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) RetroX
Reply #1 Posted on: December 31, 2010, 12:42:19 am

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Confirmed not working.  I know why, though.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) RetroX
Reply #2 Posted on: January 01, 2011, 07:27:59 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Wow, I can't get this to work.

Here's my code, and if anyone wants to see if they can fix it, go ahead:

Code: [Select]
#define EPSILON 1e-14

int move_contact(double direction, double max_distance, bool solid_only)
{
  enigma::object_collisions* inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->y + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->y + inst1->bbox_bottom;
  double max_x = lengthdir_x(max_distance, direction);
  double max_y = lengthdir_y(max_distance, direction);
  double moving_x = inst1->x + max_x;
  double moving_y = inst1->y + max_y;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(all); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst2->id == inst1->id || solid_only && !inst2->solid) continue;
    const double left2  = inst2->x + inst2->bbox_left,  top2    = inst2->y + inst2->bbox_top,
                 right2 = inst2->x + inst2->bbox_right, bottom2 = inst2->y + inst2->bbox_bottom;
    const double x_moving = inst1->x + max_x;
    if (inst1->y < bottom2 && inst1->y > top2)
    {
      if (max_x > EPSILON)
      {
        if (left2 < moving_x)
        {
          max_x    = left2 - inst1->x;
          moving_x = inst1->x + max_x;
        }
      }
      else if (max_x < -EPSILON)
      {
        if (right2 > moving_x)
        {
          max_x    = right2 - inst1->x;
          moving_x = inst1->x + max_x;
        }
      }
    }

    if (inst1->x < right2 && inst1->x > left2)
    {
      if (max_y > EPSILON)
      {
        if (top2 < moving_y)
        {
          max_y    = left2 - inst1->y;
          moving_y = inst1->y + max_y;
        }
      }
      else if (max_y < -EPSILON)
      {
        if (bottom2 > moving_y)
        {
          max_y    = bottom2 - inst1->y;
          moving_y = inst1->y + max_y;
        }
      }
    }
  }

  inst1->x = moving_x;
  inst1->y = moving_y;

  return 0;
}

inline int move_contact_solid(double direction, double speed) { return move_contact(direction, speed, true); }
inline int move_contact_all(double direction, double speed)   { return move_contact(direction, speed, false); }
« Last Edit: January 01, 2011, 09:32:31 pm by RetroX » Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Female) IsmAvatar
Reply #3 Posted on: January 01, 2011, 09:29:49 pm

LateralGM Developer
LGM Developer
Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 877

View Profile Email
I like these lines of code:

  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->x + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->x + inst1->bbox_bottom;

    const double left2  = inst2->x + inst2->bbox_left,  top2    = inst2->x + inst2->bbox_top,
                 right2 = inst2->x + inst2->bbox_right, bottom2 = inst2->x + inst2->bbox_bottom;
Logged
Offline (Male) RetroX
Reply #4 Posted on: January 01, 2011, 09:33:15 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Code: [Select]
#define EPSILON 1e-14

int move_contact(double direction, double max_distance, bool solid_only)
{
  enigma::object_collisions* inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->y + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->y + inst1->bbox_bottom;
  double max_x = lengthdir_x(max_distance, direction);
  double max_y = lengthdir_y(max_distance, direction);
  double moving_x = inst1->x + max_x;
  double moving_y = inst1->y + max_y;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(all); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst2->id == inst1->id || solid_only && !inst2->solid) continue;
    const double left2  = inst2->x + inst2->bbox_left,  top2    = inst2->y + inst2->bbox_top,
                 right2 = inst2->x + inst2->bbox_right, bottom2 = inst2->y + inst2->bbox_bottom;
    const double x_moving = inst1->x + max_x;
    if (inst1->y < bottom2 && inst1->y > top2)
    {
      if (max_x > EPSILON)
      {
        if (left2 < moving_x)
        {
          max_x    = left2 - inst1->x;
          moving_x = inst1->x + max_x;
        }
      }
      else if (max_x < -EPSILON)
      {
        if (right2 > moving_x)
        {
          max_x    = right2 - inst1->x;
          moving_x = inst1->x + max_x;
        }
      }
    }

    if (inst1->x < right2 && inst1->x > left2)
    {
      if (max_y > EPSILON)
      {
        if (top2 < moving_y)
        {
          max_y    = top2 - inst1->y;
          moving_y = inst1->y + max_y;
        }
      }
      else if (max_y < -EPSILON)
      {
        if (bottom2 > moving_y)
        {
          max_y    = bottom2 - inst1->y;
          moving_y = inst1->y + max_y;
        }
      }
    }
  }

  inst1->x = moving_x;
  inst1->y = moving_y;

  return 0;
}

inline int move_contact_solid(double direction, double speed) { return move_contact(direction, speed, true); }
inline int move_contact_all(double direction, double speed)   { return move_contact(direction, speed, false); }
I know why this doesn't work, but I'm working on something else atm.  Will fix later; bug me on the IRC if I don't.
« Last Edit: January 01, 2011, 09:42:36 pm by RetroX » Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) RetroX
Reply #5 Posted on: January 02, 2011, 06:50:32 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
Code: [Select]
#define EPSILON 1e-14

int move_contact(double direction, double max_distance, int object, bool solid_only)
{
  enigma::object_collisions* inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->x + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->x + inst1->bbox_bottom;
  double max_x = lengthdir_x(max_distance, direction);
  double max_y = lengthdir_y(max_distance, direction);
  double moving_left1  = left1  + max_x, moving_top1    = top1    + max_y,
         moving_right1 = right1 + max_x, moving_bottom1 = bottom1 + max_y;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(all); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst2->id == inst1->id || solid_only && !inst2->solid) continue;
    const double left2  = inst2->x + inst2->bbox_left,  top2    = inst2->x + inst2->bbox_top,
                 right2 = inst2->x + inst2->bbox_right, bottom2 = inst2->x + inst2->bbox_bottom;
    if (top1 < bottom2 && bottom1 > top2)
    {
      if (max_x > EPSILON)
      {
        if (left2 < moving_right1)
        {
          max_x         = left2 - moving_right1;
          moving_left1  = left1  + max_x;
          moving_right1 = right1 + max_x;
        }
      }
      else if (max_x < -EPSILON)
      {
        if (right2 > moving_left1)
        {
          max_x         = right2 - moving_left1;
          moving_left1  = left1  + max_x;
          moving_right1 = right1 + max_x;
        }
      }
    }

    if (left1 < right2 && right1 > left2)
    {
      if (max_y > EPSILON)
      {
        if (top2 < moving_top1)
        {
          max_y          = top2 - moving_bottom1;
          moving_top1    = top1    + max_y;
          moving_bottom1 = bottom1 + max_y;
        }
      }
      else if (max_y < -EPSILON)
      {
        if (bottom2 > moving_bottom1)
        {
          max_y          = bottom2 - moving_top1;
          moving_top1    = top1    + max_y;
          moving_bottom1 = bottom1 + max_y;
        }
      }
    }
  }

  inst1->x += max_x;
  inst1->y += max_y;

  return 0;
}

inline int move_contact_solid(double direction, double speed)              { return move_contact(direction, speed, all, true); }
inline int move_contact_all(double direction, double speed)                { return move_contact(direction, speed, all, false); }
inline int move_contact_object(double direction, double speed, int object) { return move_contact(direction, speed, object, false); }

Now, I don't know why this is spazzing all over the place.  Will figure out later, or someone else can do it.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) RetroX
Reply #6 Posted on: January 02, 2011, 07:41:55 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
lol:
Code: [Select]
#define EPSILON 1e-14

int move_contact(double direction, double max_distance, int object, bool solid_only)
{
  enigma::object_collisions* inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst);
  const double left1  = inst1->x + inst1->bbox_left,  top1    = inst1->y + inst1->bbox_top,
               right1 = inst1->x + inst1->bbox_right, bottom1 = inst1->y + inst1->bbox_bottom;
  double max_x = lengthdir_x(max_distance, direction);
  double max_y = lengthdir_y(max_distance, direction);
  double moving_left1  = left1  + max_x, moving_top1    = top1    + max_y,
         moving_right1 = right1 + max_x, moving_bottom1 = bottom1 + max_y;
  for (enigma::inst_iter *it = enigma::fetch_inst_iter_by_int(all); it != NULL; it = it->next)
  {
    const enigma::object_collisions* inst2 = (enigma::object_collisions*)it->inst;
    if (inst2->id == inst1->id || solid_only && !inst2->solid) continue;
    const double left2  = inst2->x + inst2->bbox_left,  top2    = inst2->y + inst2->bbox_top,
                 right2 = inst2->x + inst2->bbox_right, bottom2 = inst2->y + inst2->bbox_bottom;
    if (top1 < bottom2 && bottom1 > top2)
    {
      if (max_x > EPSILON)
      {
        if (left2 < moving_right1)
        {
          max_x         = left2 - moving_right1;
          moving_left1  = left1  + max_x;
          moving_right1 = right1 + max_x;
        }
      }
      else if (max_x < -EPSILON)
      {
        if (right2 > moving_left1)
        {
          max_x         = right2 - moving_left1;
          moving_left1  = left1  + max_x;
          moving_right1 = right1 + max_x;
        }
      }
    }

    if (left1 < right2 && right1 > left2)
    {
      if (max_y > EPSILON)
      {
        if (top2 < moving_top1)
        {
          max_y          = top2 - moving_bottom1;
          moving_top1    = top1    + max_y;
          moving_bottom1 = bottom1 + max_y;
        }
      }
      else if (max_y < -EPSILON)
      {
        if (bottom2 > moving_bottom1)
        {
          max_y          = bottom2 - moving_top1;
          moving_top1    = top1    + max_y;
          moving_bottom1 = bottom1 + max_y;
        }
      }
    }
  }

  inst1->x += max_x;
  inst1->y += max_y;

  return 0;
}

inline int move_contact_solid(double direction, double speed)              { return move_contact(direction, speed, all, true); }
inline int move_contact_all(double direction, double speed)                { return move_contact(direction, speed, all, false); }
inline int move_contact_object(double direction, double speed, int object) { return move_contact(direction, speed, object, false); }
still doesn't work.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) polygone
Reply #7 Posted on: January 02, 2011, 08:54:34 pm

Contributor
Location: England
Joined: Mar 2009
Posts: 794

View Profile
I think you wanted this:

Code: [Select]
    if (top1 < bottom2 && bottom1 > top2)
    {
      if (max_x > EPSILON)
      {
        if (moving_right1 > left2)
        {
          max_x         = left2 - moving_right1;
          moving_left1  = left1  + max_x;
          moving_right1 = right1 + max_x;
        }
      }
      else if (max_x < -EPSILON)
      {
        if (moving_left1 < right2)
        {
          max_x         = right2 - moving_left1;
          moving_left1  = left1  + max_x;
          moving_right1 = right1 + max_x;
        }
      }
    }

    if (left1 < right2 && right1 > left2)
    {
      if (max_y > EPSILON)
      {
        if (moving_bottom1 > top2)
        {
          max_y          = top2 - moving_bottom1;
          moving_top1    = top1    + max_y;
          moving_bottom1 = bottom1 + max_y;
        }
      }
      else if (max_y < -EPSILON)
      {
        if (moving_top1 < bottom2)
        {
          max_y          = bottom2 - moving_top1;
          moving_top1    = top1    + max_y;
          moving_bottom1 = bottom1 + max_y;
        }
      }
    }

But after actually reading the code for the first time I have a number of issues with this method anyway.

1. You can collide into an object from a position where neither this (top1 < bottom2 && bottom1 > top2) or (left1 < right2 && right1 > left2) is satisfied.
2. The max_x, max_y variables are not actually set to the correct values for moving to the position where the collision occurs.
3. You can 'skip' right through objects if the distance is set large enough, which is contrary to what move_contact should do.
4. It doesn't allow for precise collision checks only bbox checks.

Although this method is often faster, I don't think it is exactly correct to use. I would suggest writing a more precise method using place_meeting.
Logged
I honestly don't know wtf I'm talking about but hopefully I can muddle my way through.
Offline (Male) RetroX
Reply #8 Posted on: January 02, 2011, 08:57:14 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
I would suggest writing a more precise method using place_meeting.
The point of this was to avoid using a massive, inefficient for loop. (that)

I've basically given up at this point, so, anyone else can either fix mine or toss it and make a new one.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) polygone
Reply #9 Posted on: January 02, 2011, 09:06:15 pm

Contributor
Location: England
Joined: Mar 2009
Posts: 794

View Profile
I know the point is to make it more efficient, but without doing an "inefficient loop" it's not exact going to be doing it's job.
« Last Edit: January 03, 2011, 12:16:20 am by polygone » Logged
I honestly don't know wtf I'm talking about but hopefully I can muddle my way through.
Offline (Male) RetroX
Reply #10 Posted on: January 02, 2011, 09:56:05 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
I know the point is to make it more efficient, but without doing an inefficient loop it's not exact going to be doing it's job.
It can be done.  It's just that I'm doing it incorrectly.
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) Josh @ Dreamland
Reply #11 Posted on: January 02, 2011, 11:59:33 pm

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2950

View Profile Email
A for loop is unnecessary with bboxes.
1) Calculate furthest bbox point when translated from the untranslated position.
i.     If your bottom-left corner is at (0,0) and you are 32x32 pixels, and you are checking 10px at 45 degrees, the coordinate you want is 10*cos(45 deg) + 32, 10*sin(45 deg) + 32
2) Loop, looking for solid objects that collide with box from the two furthest points ((0,0) and (10*cos(45 deg) + 32, 10*sin(45 deg) + 32) in our example)
3) Check untranslated rectangle for collisions; if you're colliding with it initially, we obviously can't move any closer, so break.ass
4) Switch the quadrant of our angle (wrap(angle,360) / 90). This code assumes inst is the current instance and inst1 is the instance we're looping through. Neither are translated from their original position. It assumes a variable representing total displacement, dt. distSquared is parameter dist * parameter dist.
Code: (C++) [Select]
case 0: // Quadrant 0; horizontal up to nearly vertical
  const int dx = inst2->bbox_left - inst->bbox_right; // Get horizontal distance
  const int tdt = (dx >= 0)?dx/cos(45) : (inst2->bbox_bottom - inst->bbox_top)*sin(45);
  if (tdt < td)
    td = tdt;

I lack time to do the other three quadrants. You can do them and debug, or I will later. Peace.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) polygone
Reply #12 Posted on: January 03, 2011, 06:27:35 am

Contributor
Location: England
Joined: Mar 2009
Posts: 794

View Profile
You can't easily check for 'solid objects that collide with box from the two furthest points' when only using one reference point on the bbox. I have wrote it instead using two reference points on the bbox (at opposite ends) then you can easily check objects that will collide via the angles. Here is working code in gml:

Code: (EDL) [Select]
//move_contact_bbox(angle, distance, object)
var angle, dist;
angle = argument0;  dist = argument1;

with (argument2)
{
  if (bbox_right >= other.bbox_left && bbox_bottom >= other.bbox_top && bbox_left <= other.bbox_right && bbox_top <= other.bbox_bottom)
  {
    dist = 0;
    break;
  }

  switch (wrap(angle, 360) div 90)
  {
    case 0:
      if ((bbox_left > other.bbox_right || other.bbox_top > bbox_bottom) &&
      angle_difference(point_direction(other.bbox_right, other.bbox_bottom, bbox_left, bbox_top), angle) >= 0  &&
      angle_difference(point_direction(other.bbox_left, other.bbox_top, bbox_right, bbox_bottom), angle) <= 0)
      {
        if (angle_difference(point_direction(other.bbox_right, other.bbox_top, bbox_left, bbox_bottom), angle) > 0)
        {
          dist = min(dist, (other.bbox_top - bbox_bottom - 1)/sin(degtorad(angle)));
        }
        else
        {
          dist = min(dist, (bbox_left - other.bbox_right - 1)/cos(degtorad(angle)));
        }
      }
    break;

    case 1:
      if ((other.bbox_left > bbox_right || other.bbox_top > bbox_bottom) &&
      angle_difference(point_direction(other.bbox_left, other.bbox_bottom, bbox_right, bbox_top), angle) <= 0  &&
      angle_difference(point_direction(other.bbox_right, other.bbox_top, bbox_left, bbox_bottom), angle) >= 0)
      {
        if (angle_difference(point_direction(other.bbox_left, other.bbox_top, bbox_right, bbox_bottom), angle) > 0)
        {
          dist = min(dist, (bbox_right - other.bbox_left + 1)/cos(degtorad(angle)));
        }
        else
        {
          dist = min(dist, (other.bbox_top - bbox_bottom - 1)/sin(degtorad(angle)));
        }
      }
    break;

    case 2:
      if ((other.bbox_left > bbox_right || bbox_top > other.bbox_bottom) &&
      angle_difference(point_direction(other.bbox_right, other.bbox_bottom, bbox_left, bbox_top), angle) <= 0  &&
      angle_difference(point_direction(other.bbox_left, other.bbox_top, bbox_right, bbox_bottom), angle) >= 0)
      {
        if (angle_difference(point_direction(other.bbox_left, other.bbox_bottom, bbox_right, bbox_top), angle) > 0)
        {
          dist = min(dist, (other.bbox_bottom - bbox_top + 1)/sin(degtorad(angle)));
        }
        else
        {
          dist = min(dist, (bbox_right - other.bbox_left + 1)/cos(degtorad(angle)));
        }
      }
    break;

    case 3:
      if ((bbox_left > other.bbox_right || bbox_top > other.bbox_bottom) &&
      angle_difference(point_direction(other.bbox_right, other.bbox_top, bbox_left, bbox_bottom), angle) <= 0  &&
      angle_difference(point_direction(other.bbox_left, other.bbox_bottom, bbox_right, bbox_top), angle) >= 0)
      {
        if (angle_difference(point_direction(other.bbox_right, other.bbox_bottom, bbox_left, bbox_top), angle) > 0)
        {
          dist = min(dist, (bbox_left - other.bbox_right - 1)/cos(degtorad(angle)));
        }
        else
        {
          dist = min(dist, (other.bbox_bottom - bbox_top + 1)/sin(degtorad(angle)));
        }
      }
    break;
  }
}

x += cos(degtorad(angle))*dist;  y -= sin(degtorad(angle))*dist;
Here is the example file I was working with if anyone wants to check that it works:
http://www.box.net/shared/popdzld7rp (GM8 gmk)

Press M to move_contact, press Space to change the movement direction, Press R to move the instance back to it's starting position.

I will attempt a write of it in C++ at some point.
« Last Edit: January 03, 2011, 07:37:41 am by polygone » Logged
I honestly don't know wtf I'm talking about but hopefully I can muddle my way through.
Offline (Male) Josh @ Dreamland
Reply #13 Posted on: January 03, 2011, 12:22:31 pm

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2950

View Profile Email
>You can't easily check for 'solid objects that collide with box from the two furthest points' when only using one reference point on the bbox.

Yes, you can. That's why I broke it into quadrants. I didn't have time to sketch up my idea yesterday (or even to draft it fully), but today, I do.

http://dl.dropbox.com/u/1052740/MoveBboxSolid.png

Code: (C++) [Select]
case 0: // Quadrant 0; horizontal up to nearly vertical
  const int dx = inst2->bbox_left - inst->bbox_right, dy = inst2->bbox_bottom - inst->bbox_top; // Get horizontal distance
  const int tdt = (dx > dy)?  dx/cos(dir) : dy*sin(dir);
  if (tdt < td and /*a rectangle that is our translated rectangle with a 1px border collides with our inst2->bbox*/ true)
    td = tdt;
« Last Edit: January 03, 2011, 01:12:24 pm by Josh @ Dreamland » Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) polygone
Reply #14 Posted on: January 03, 2011, 12:25:19 pm

Contributor
Location: England
Joined: Mar 2009
Posts: 794

View Profile
I don't exactly get what you're doing, I'll wait till I see it finished...

EDIT: OK I see that with this code:

Code: (C++) [Select]
const int dx = inst2->bbox_left - inst->bbox_right, dy = inst2->bbox_bottom - inst->bbox_top
const int tdt = (dx > dy)?  dx/cos(dir) : dy*sin(dir);
  if (tdt < td)
    td = tdt;
You are trying to do the exact same thing as I did with this code:

Code: (EDL) [Select]
        if (angle_difference(point_direction(other.bbox_right, other.bbox_top, bbox_left, bbox_bottom), angle) > 0)
        {
          dist = min(dist, (other.bbox_top - bbox_bottom - 1)/sin(degtorad(angle)));
        }
        else
        {
          dist = min(dist, (bbox_left - other.bbox_right - 1)/cos(degtorad(angle)));
        }
I do not think what you used works though, I believe you have to check the angle against the dir in order to determine the correct colliding side with the instance.

I think the method I have used is actually the same method as the one in your head, but I don't see how you can work it without checking the angles.

EDIT 2: Let me make an image, it might be easier to explain:
http://img403.imageshack.us/img403/5790/bboxmovement.png

The red arrows represent two different directions the object could move in from the same position, each direction will result in a different side being collided yet dx, dy are exactly the same. Can you see why I decided to check the angle then instead?
« Last Edit: January 03, 2011, 01:53:25 pm by polygone » Logged
I honestly don't know wtf I'm talking about but hopefully I can muddle my way through.
Pages: 1 2 »
  Print