Author Topic: Checking if any object is within a range of coordinates  (Read 544 times)  Share 

Andail

  • Global Moderator
  • Mittens Baronet
  • Cultured man of mystery
    • I can help with backgrounds
    •  
Basically I would like to use something like
Code: Adventure Game Studio
  1. if (Object.GetAtScreenXY (and here insert a range of x coordinates, and then a range of y coordinates, which will constitute an area) != null){
  2. }
  3.  
I've been scripting all day and getting a bit disoriented, so this could probably be rather easy. Alternatively, I could draw regions or hotspots and check whether any objects has ended up on top of them.
Be vigilant, citizen!
Check out my GiP, The Samaritan Paradox
Also, check my blog at http://faravidinteractive.wordpress.com/

geork

  • measure once, cut twice, say it was already broken
    • I can help with scripting
    •  
    • I can help with voice acting
    •  
Re: Checking if any object is within a range of coordinates
« Reply #1 on: 08 Aug 2012, 20:13 »
I've scripted a short piece of code which should work to this:
Code: Adventure Game Studio
  1. //Somewhere
  2. bool GetObjectsInArea(int StartX, int StartY, int EndX, int EndY){
  3.   bool FoundObject = false;
  4.   while(StartX != EndX && StartY != EndY){
  5.     if(Object.GetAtScreenXY(StartX, StartY) != null) FoundObject = true;
  6.     if(StartX != EndX) StartX ++;
  7.     if(StartY != EndY) StartY ++;
  8.   }
  9.   return FoundObject;
  10. }
  11. //Somewhere else
  12. if(GetObjectsInArea(X, Y, X2, Y2) == true){
  13. }

I've tested this very roughly, but it seems to be working. I guess to store the objects found you can make an array and add an item every time the Object.GetAtScreenXY condition is true.

Hope that works!

Andail

  • Global Moderator
  • Mittens Baronet
  • Cultured man of mystery
    • I can help with backgrounds
    •  
Re: Checking if any object is within a range of coordinates
« Reply #2 on: 08 Aug 2012, 20:27 »
Wow, thanks :) I tried it quickly and it seems to do the trick! Will return otherwise.
Thanks again!
Be vigilant, citizen!
Check out my GiP, The Samaritan Paradox
Also, check my blog at http://faravidinteractive.wordpress.com/

Crimson Wizard

  • AGS Project Admins
  • not et suppotreD
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #3 on: 08 Aug 2012, 20:28 »
I guess since the number of objects in the room is usually less than number of pixels in the range, it would be simplier (and faster - runtime-wise) to iterate through objects array instead, like:

Code: Adventure Game Studio
  1.    int index = 0;
  2.    while (index < Room.ObjectCount)
  3.    {
  4.      Object *o = object[index];
  5.      if (object[index].X >= RANGE_X_MIN && object[index].X <= RANGE_X_MAX &&
  6.          object[index].Y >= RANGE_Y_MIN && object[index].Y <= RANGE_Y_MAX)
  7.      {
  8.        return o;
  9.      }
  10.      index++;
  11.    }
  12.  

Andail

  • Global Moderator
  • Mittens Baronet
  • Cultured man of mystery
    • I can help with backgrounds
    •  
Re: Checking if any object is within a range of coordinates
« Reply #4 on: 08 Aug 2012, 20:56 »
Crimson, how do I implement this? I get that it's testing all objects in the room to check whether they're in the ranges, but if I have 8 areas, how do I check if all of these areas have objects in them?
Be vigilant, citizen!
Check out my GiP, The Samaritan Paradox
Also, check my blog at http://faravidinteractive.wordpress.com/

Crimson Wizard

  • AGS Project Admins
  • not et suppotreD
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #5 on: 08 Aug 2012, 21:03 »
Ah, well, if we are to use geork's code structure as an example:
Code: Adventure Game Studio
  1.  
  2. Object *GetFirstFoundObjectInArea(int StartX, int StartY, int EndX, int EndY) {
  3.    int index = 0;
  4.    while (index < Room.ObjectCount)
  5.    {
  6.      Object *o = object[index];
  7.      if (o.X >= StartX && o.X <= EndX &&
  8.          o.Y >= StartY && o.Y <= EndY)
  9.      {
  10.        return o;
  11.      }
  12.      index++;
  13.    }
  14.    return null;
  15. }
  16. //Somewhere else
  17. Object *o = GetFirstFoundObjectInArea(X, Y, X2, Y2);
  18. if(o != null){
  19. // there's some object
  20. }
  21.  

Still I wonder, do you need to find ANY object, or all of the objects? In the latter case this code won't work as-is.

EDIT: heh, noticed I did not make use of "o" variable in the loop, fixed the code a little.
« Last Edit: 08 Aug 2012, 21:08 by Crimson Wizard »

Andail

  • Global Moderator
  • Mittens Baronet
  • Cultured man of mystery
    • I can help with backgrounds
    •  
Re: Checking if any object is within a range of coordinates
« Reply #6 on: 08 Aug 2012, 21:15 »
Well, all the objects have to be placed in any of the areas. But it doesn't matter which object is in which area.

So, any object in any area, but every object needs to be in one area.

I think Geork's solution suits me well now, and this is only in one little room anyway, so I don't think the computer will be slowed down.
Thanks a lot, still :)
Be vigilant, citizen!
Check out my GiP, The Samaritan Paradox
Also, check my blog at http://faravidinteractive.wordpress.com/

Crimson Wizard

  • AGS Project Admins
  • not et suppotreD
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #7 on: 09 Aug 2012, 01:44 »
Erm, I suddenly realized my implementation is wrong. :P

What I do is checking Object's position, but object is a box at best, and it's not always represented by rectangular sprite.

Snarky

  • Global Moderator
  • Mittens Baronet
  • Private Insultant
    • I can help with proof reading
    •  
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #8 on: 09 Aug 2012, 09:28 »
There's a mistake in geork's solutions as well. He increments both the X and Y coordinates in a single loop, so the code actually only checks along the diagonal of the region. In order to check every single pixel, you need two loops, an inner loop that goes through all the X coordinates (for example), and an outer loop that goes through all the Y coordinates (running the inner X loop for each of them).

However, this will probably be hideously slow. I would use Crimson Wizard's solution and check whether the object sprite bounding boxes intersect with the region. If that's not good enough, you could then run through only the intersecting regions using (a corrected version of) geork's solution.

Isn't there already a function or module for pixel-perfect collision detection, though? That's essentially what you're trying to do, so maybe you can use that.

The other way to go about this is to rethink your approach. You say every object has to be in one of the regions? Then can you not just keep track of which one you place them in initially (e.g. storing it in a custom object property) and update it whenever they move? Also, how do you ensure that an object isn't in two areas at the same time?
« Last Edit: 09 Aug 2012, 09:39 by Snarky »

geork

  • measure once, cut twice, say it was already broken
    • I can help with scripting
    •  
    • I can help with voice acting
    •  
Re: Checking if any object is within a range of coordinates
« Reply #9 on: 09 Aug 2012, 12:11 »
Oops, my bad :P

Crimson's solution is way more elegant. If we can assume that the objects are bound by rectangles, then a slight amendment could work maybe?
Code: Adventure Game Studio
  1. Object *GetFirstFoundObjectInArea(int StartX, int StartY, int EndX, int EndY){
  2.   int index = 0;
  3.   while(index < Room.ObjectCount){
  4.     Object *o = object[index];
  5.     DynamicSprite *f = DynamicSprite.CreateFromExistingSprite(o.Graphic);
  6.     int Xfactor = f.Width;
  7.     int Yfactor = f.Height;
  8.     f.Delete(); // I don't know whether the above 2 are needed, but want to delete the sprite before the function is cut off
  9.     if((o.X >= StartX || o.X + Xfactor >= StartX) &&
  10.        (o.X <= EndX || o.X + Xfactor <= EndX) &&
  11.        (o.Y >= StartY || o.Y + Yfactor >= StartX) &&
  12.        (o.Y >= EndY || o.Y + Yfactor <= EndY)) return o;
  13.     index ++;
  14.   }
  15.   return null;
  16. }
I tested this on an object which was only partially covered (ie not the XY coordinate) by the box and it seemed to work well enough. I guess for extra safety one could put brackets around the o.X/Y + f.Width/Height

This ain't pixel perfect though.

Crimson Wizard

  • AGS Project Admins
  • not et suppotreD
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #10 on: 09 Aug 2012, 12:33 »
@geork, you seem to like heavy programs :)
Code: Adventure Game Studio
  1. DynamicSprite *f = DynamicSprite.CreateFromExistingSprite(o.Graphic);
  2. int Xfactor = f.Width;
  3. int Yfactor = f.Height;
  4.  

Shouldn't this be better?
Code: Adventure Game Studio
  1. int Xfactor = Game.SpriteWidth[o.Graphic];
  2. int Xfactor = Game.SpriteHeight[o.Graphic];
  3.  

Khris

  • Evil Dark Emperor Death-Kill
    • Lifetime Achievement Award Winner
    •  
    • I can help with play testing
    •  
    • I can help with scripting
    •  
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #11 on: 09 Aug 2012, 12:51 »
In order to get an object's sprite dimensions you don't need to create a DynamicSprite.
You can use this:
Code: Adventure Game Studio
  1.   int slot = oCurrentObject.Graphic;
  2.   int w = Game.SpriteWidth[slot], h = Game.SpriteHeight[slot];

Regarding the approach: I'd find the shortest distance of all the objects' center points from the area's center point.

Code: Adventure Game Studio
  1. Object*GetObjectInsideArea(int x1, int y1, int x2, int y2) {
  2.   int xc = (x1+x2)/2;
  3.   int yc = (y1+y2)/2;
  4.   int i;
  5.   int fo = -1;
  6.   int fd = 99999;
  7.   int foxd, foyd;
  8.   while (i < Room.ObjectCount) {
  9.     int oxd = (object[i].X + Game.SpriteWidth[object[i].Graphic]/2) - xc;
  10.     int oyd = (object[i].Y - Game.SpriteHeight[object[i].Graphic]/2) - yc;
  11.     int d = FloatToInt(Maths.Sqrt(IntToFloat(oxd*oxd + oyd*oyd)), eRoundNearest);
  12.     if (d < fd) {
  13.       fd = d;
  14.       fo = i;
  15.       foxd = oxd;
  16.       foyd = oyd;
  17.     }
  18.     i++;
  19.   }  
  20.   if (fo == -1) return null;
  21.   // treshold
  22.   // x
  23.   int w = Game.SpriteWidth[object[fo].Graphic];
  24.   if (x1 < x2) w += (x2-x1); else w += (x1-x2);
  25.   w = w/2;
  26.   if (foxd < 0) foxd = -foxd;
  27.   // y
  28.   int h = Game.SpriteHeight[object[fo].Graphic];
  29.   if (y1 < y2) h += (y2-y1); else h += (y1-y2);
  30.   h = h/2;
  31.   if (foyd < 0) foyd = -foyd;
  32.  
  33.   if (foxd <= w && foyd <= h) return object[fo];
  34.   return null;
  35. }

Tested and working. Gives best results if all objects are of similar size.

Edit:
Here's another approach, this one calculates the area of the overlap and returns the object with the biggest one.
Code: Adventure Game Studio
  1. Object*GetObjectOverlappingArea(int x1, int y1, int x2, int y2) {
  2.   int xc = (x1+x2)/2;
  3.   int yc = (y1+y2)/2;
  4.   int aw = x2 - x1;
  5.   if (aw < 0) aw = -aw;
  6.   int ah = y2 - y1;
  7.   if (ah < 0) ah = -ah;
  8.   int i;
  9.   int fo = -1;
  10.   int foa = 0;
  11.   int foxd, foyd;
  12.   while (i < Room.ObjectCount) {
  13.     int ow = Game.SpriteWidth[object[i].Graphic];
  14.     int oh = Game.SpriteHeight[object[i].Graphic];
  15.     int xd = (object[i].X + ow/2) - xc; if (xd < 0) xd = -xd;
  16.     int yd = (object[i].Y - oh/2) - yc; if (yd < 0) yd = -yd;
  17.     int w = (ow + aw)/2;
  18.     int h = (oh + ah)/2;
  19.     int ovx = w - xd; if (ovx > aw) ovx = aw; if (ovx > ow) ovx = ow;
  20.     int ovy = h - yd; if (ovy > ah) ovy = ah; if (ovy > oh) ovy = oh;
  21.     if (ovx > 0 && ovy > 0 && ovx*ovy > foa) {
  22.       fo = i;
  23.       foa = ovx*ovy;
  24.     }
  25.     i++;
  26.   }
  27.   if (fo == -1) return null;
  28.   return object[fo];
  29. }

If the objects are of all kinds of different sizes, use the latter.

Edit2:
The second approach can be coded much easier using AGS's AreThingsOverlapping, since the int returned is the bigger the bigger the overlap (and I guess it's the number of pixels). But that would require a dummy character and a dummy view to assign the rectangular sprite to and that seems a bit of an annoying requirement.
« Last Edit: 09 Aug 2012, 14:19 by Khris »
http://whathaveyoutried.com/

The other day on yahoo answers:
"Can you print colored images with black ink? If so tell me how please Thanx Kimberly"

Snarky

  • Global Moderator
  • Mittens Baronet
  • Private Insultant
    • I can help with proof reading
    •  
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #12 on: 09 Aug 2012, 14:21 »
In other words: We don't have enough information about what you're trying to do to recommend a best solution. (Mainly, what shapes are the objects, and how are the areas laid out?)

Andail

  • Global Moderator
  • Mittens Baronet
  • Cultured man of mystery
    • I can help with backgrounds
    •  
Re: Checking if any object is within a range of coordinates
« Reply #13 on: 09 Aug 2012, 14:57 »
I don't want to spoil my game by telling exactly, but this should be enough:
* All objects are identical
* They need to be positioned on certain areas, which are also identical, and which have been drawn so that the objects should fit with a few pixels margin
* When all objects have been moved around so that they are in the correct areas, a function will be triggered

Let's say that I've drawn a hundred holes on a golf green, seen from above, and there are eight balls. All the balls are objects that can be dragged and dropped with the mouse. The player needs to move all the balls so that they fit into the correct eight holes. How best check if the correct eight holes have balls in them?

Note: Everything else is neatly scripted and working splendidly, I just need an effective way to check the result. Geork's solution works satisfactorily, since the player will intuitively place the object neatly in the area anyhow, but it does allow the objects to be placed very imperfectly and still trigger the if-function.
Be vigilant, citizen!
Check out my GiP, The Samaritan Paradox
Also, check my blog at http://faravidinteractive.wordpress.com/

Khris

  • Evil Dark Emperor Death-Kill
    • Lifetime Achievement Award Winner
    •  
    • I can help with play testing
    •  
    • I can help with scripting
    •  
    • I can help with translating
    •  
Re: Checking if any object is within a range of coordinates
« Reply #14 on: 09 Aug 2012, 16:43 »
I'd make the balls snap into position by keeping an array of hole coords.
Also, whenever a ball is placed in a hole, mark the hole as occupied.

Like this:
Code: Adventure Game Studio
  1. struct str_holes {
  2.   int center_x, center_y;
  3.   int ball;  //  -1: no ball, 0-X: ball 0-X
  4. }

Now all you need to do is whenever a ball is dropped, check the distance to all holes. If one is close and free, move the ball to its center and set hole[
http://whathaveyoutried.com/

The other day on yahoo answers:
"Can you print colored images with black ink? If so tell me how please Thanx Kimberly"