Noob Scripting issue

Started by Babar, Wed 19/12/2012 12:06:33

Previous topic - Next topic

Babar

Hello everyone!
Been a long while since I posted in this forum...please don't hurt me too much :D.

So I'm trying to find the leftmost and rightmost x value of all the hotspots in any one room. This is what I have so far (runs in room_Load()):
Code: AGS

  int cc=0, x=0, y=0;
  int hmin[50];
  int hmax[50];
  int IDmax=0;
  Hotspot* HatXY;
  while (cc<50)                            //Initialising array
  {
    hmin[cc]=Room.Width;
    hmax[cc]=0;
    cc++;
  }
 
  while (y<Room.Height)
  {
    while (x<Room.Width)                    //Going through Room pixel by pixel to find width of all hotspots
    {
      HatXY=Hotspot.GetAtScreenXY(x, y);
      if (HatXY!=hotspot[0])
      {
        if (HatXY.ID>IDmax) IDmax=HatXY.ID;
        if (x<hmin[HatXY.ID]) hmin[HatXY.ID]=x;//Gets minimum x value of hotspot HatXY
        if (x<hmax[HatXY.ID]) hmax[HatXY.ID]=x;//Gets maximum x value of hotspot HatXY
      }
      x++;
    }
    y++;
  }

And it doesn't work. I've checked with debugging, but putting a breakpoint inside the if, but it never enters into the "if (HatXY!=hotspot[0]) {...}" condition. I had replaced "hotspot[0]" with "null", that didn't help either. My room DOES have hotspots and it is NOT a scrolling room (although I'm curious if that matters if the viewport is set to zero). I tried putting the code in room_AfterFadeIn() as well, but it still didn't work. I randomly tried declaring the pointer inside the loop, and even assigning the GetAtScreenXY value outside the loop, it doesn't work.

Could someone please tell me, or help me figure out what the problem is?
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Crimson Wizard

#1
Quote from: Babar on Wed 19/12/2012 12:06:33
Been a long while since I posted in this forum...please don't hurt me too much :D.
So, you are making a game?! Like Alien Time Zone 2? :)

Regarding your question.

You should initialize x with 0 every time before the X loop, since you must start from the beginning of horizontal line:
Code: ags

while (y<Room.Height)
{
  x = 0;   <---------------------- this
  while (x<Room.Width)
  {


But then, I think there's simplier way to do this. Since you need to find only left/right-most coordinates, you'll find them faster if you will be scanning vertical lines, first from left, then from right. The first hotspot you meet is the leftmost or rightmost already, so you don't even have to keep record of found hotspots and compare their placement.

Something like this:
Code: ags

bool found_left = false;
bool found_right = false;

// Looking for leftmost coordinate:
x = 0;
while (x < Room.Width && !found_left)
{
  y = 0;
  while (y < Room.Height && !found_left)
  {
    HatXY = Hotspot.GetAtScreenXY(x, y);
    if (HatXY)
    {
       hmin = x;
       found_left = true;
    }
    y++;
  }
  x++;
}

// Looking for rightmost coordinate:
x = Room.Width - 1;
while (x >= 0 && !found_right)
{
  y = 0;
  while (y < Room.Height && !found_right)
  {
    HatXY = Hotspot.GetAtScreenXY(x, y);
    if (HatXY)
    {
       hmax = x;
       found_right = true;
    }
    y++;
  }
  x--;
}


Babar

#2
D'oh!

Stupid mistake! Thanks for telling me.
Thanks for your improvement as well!


Also, it isn't ATZ2 :(...
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Babar

#3
Sorry for the double post, but for completionness's sake, here is what I ended up with (which is totally working, which I am completely happy about), after applying some probably very unnecessary efficiencies :D:

Code: AGS

  int cc=0, x=0, y=0;
  int hmin[50];
  int hmax[50];
  int IDmax=0;
  Hotspot* HatXY;
  while (cc<50)//initialising the hotspot max and min coord arrays
  {
    hmin[cc]=Room.Width+1;
    hmax[cc]=-1;
    cc++;
  }
  
  
  while (x<Room.Width)
  {
    while (y<Room.Height)
    {
      HatXY=Hotspot.GetAtScreenXY(x, y);//Checks left side of screen for min coord of any hotspot
      if (HatXY)
      {
        if (HatXY.ID>IDmax) IDmax=HatXY.ID;//to find the total number of hotspots
        if (hmin[HatXY.ID]>Room.Width) hmin[HatXY.ID]=x;//if found and value not already filled, fills it
      }
      HatXY=Hotspot.GetAtScreenXY(Room.Width-x, y);//Checks right side of screen for max coord of any hotspot
      if (HatXY)
      {
        if (HatXY.ID>IDmax) IDmax=HatXY.ID;//to find the total number of hotspots
        if (hmax[HatXY.ID]<0) hmax[HatXY.ID]=Room.Width-x;//if found and value not already filled, fills it
      }
      y++;
    }
    x++;
    y=0;
  }


Speaking of which, is there a way to know the total number of hotspots in a room? Or total number of characters in a game? And aside from assigning custom properties and manually inputting them, there any way other to know the width of a hotspot?
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Khris

This should achieve the same result:

Code: ags
  while (x<Room.Width)
  {
    while (y<Room.Height)
    {
      HatXY=Hotspot.GetAtScreenXY(x, y);//Checks left side of screen for min coord of any hotspot
      if (HatXY.ID > 0)  // HatXY is never null, no drawn hotspot means hotspot[0] is returned
      {
        if (HatXY.ID>IDmax) IDmax=HatXY.ID;//to find the total number of hotspots
        if (x < hmin[HatXY.ID]) hmin[HatXY.ID] = x;
        if (x > hmax[HatXY.ID]) hmax[HatXY.ID] = x;
      }
      y++;
    }
    x++;
    y=0;
  }

Crimson Wizard

#5
Babar, check my post, I later edited it and added the example of what I've meant.
Your new variant is even more slow, and Khris seem to revert it to what you've started with :).


Oh well, I think I just copy code here:
Code: ags

bool found_left = false;
bool found_right = false;

// Looking for leftmost coordinate:
x = 0;
while (x < Room.Width && !found_left)
{
  y = 0;
  while (y < Room.Height && !found_left)
  {
    HatXY = Hotspot.GetAtScreenXY(x, y);
    if (HatXY)
    {
       hmin = x;
       found_left = true;
    }
    y++;
  }
  x++;
}

// Looking for rightmost coordinate:
x = Room.Width - 1;
while (x >= 0 && !found_right)
{
  y = 0;
  while (y < Room.Height && !found_right)
  {
    HatXY = Hotspot.GetAtScreenXY(x, y);
    if (HatXY)
    {
       hmax = x;
       found_right = true;
    }
    y++;
  }
  x--;
}


It is more code, but I gues it will work faster, because you don't check all screen.


Quote from: Babar
Speaking of which, is there a way to know the total number of hotspots in a room? Or total number of characters in a game?
For characters it's Game.CharacterCount. Not sure about hotspots.

Quote from: Babar
And aside from assigning custom properties and manually inputting them, there any way other to know the width of a hotspot?
No. But remember that hotspot can be any shape, and, AFAIK, it may be divided into separate parts on screen too.

Khris

I'm pretty sure Babar needs the horizontal extension of every hotspot individually, so there's no way around checking the entire screen.
It's considerably faster to only check every other or third pixel though.
It's as easy as replacing x/y++; with x/y+=3; and will make the algorithm 9 times faster.

Crimson Wizard

Ah..... ah!!!

*hitting the forehead with a hand smiley here*

For some reason I thought he needs leftmost and rightmost hotspot coordinate only.

Babar

Yeah, I need it for every hotspot, not just whichever is leftmost and rightmost, and also I use the IDmax for total number of hotspots in the room (can't find any other way yet).
And thanks for the Game.CharacterCount, I missed that!

Khris, the way I've set up the conditions, following Crimson's advice, wouldn't it catch the maximum x faster, and then skip that condition statement every time after that?
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Crimson Wizard

#9
Firstly, you should use different loop ending condition:
Code: ags

while (x < Room.Width / 2)
{
    while (y < Room.Height / 2)
    {

because you are passing the room from two sides simultaneously.

Regarding speed...
Taking one hotspot into consideration. If the both hotspot's bounds are found in left screen's part, it will be slower than your original variant. In other cases it will be somewhat faster. So, depends on how hotspots are positioned in your room(s) in general.

Babar

But would your code work with cutting the x counter in half if one of my hotspots had both bounds in one side? It would never find the leftmost coord of it, no?
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Crimson Wizard

Quote from: Babar on Wed 19/12/2012 21:23:11
But would your code work with cutting the x counter in half if one of my hotspots had both bounds in one side? It would never find the leftmost coord of it, no?
It still will find the leftmost coordinate, because you are passing the screen from right side to the middle anyway. If the hotspot is all in the rightmost part, the leftmost coord will be found after rightmost coord.

Khris

Crimson, I don't think you meant to write "Room.Height / 2" :)
Also, going to the middle and calling Hotspot.GetAtScreenXY twice won't speed up things, just complicate them.

Babar:
In theory, as soon as a hotspot's leftmost point is found, one needs to look only further to the right for the maximum x, that's correct. However, it's not possible to look for an individual hotspot; all we can do is call Hotspot.GetAtScreenXY and process the result. So this has no practical application here. (The only situation in which there would be a benefit: if there was a) a command like bool hotspot[5].IsAtScreenXY() and b) that command was much faster than the one we have. Neither is the case.)

No matter how you slice it, we have to call Hotspot.GetAtScreenXY for each (or every other, or every third) pixel. Only once though, if we pull all the info we need out of the result each time. Which is exactly what I did.

Like CW said, the only way to reduce the time is by looking for the minima from the left and the maxima from the right. However (and this is a big however), only if a) AGS knows how many hotspots to expect up front and b) the rightmost left edge is further left than the leftmost right edge, some x coordinates near the center will get skipped. In every other case, there will be lots of duplicate runs, which defeats the purpose completely.

Crimson Wizard

Yes, my mind seem to be still distracted by different idea.
Indeed, since we don't know what to expect, we cannot just stop when we found borders of some hotspot, and still will have to pass every pixel...
But hey, can't we use Custom property to set number of valid hotspots?

Khris

Like I said, we could stop the run from left to right as soon as we have found all the minima, then go from Room.Width back to that x-value. But we'd have to keep track of how many hotspots we have found and compare that to the Custom property value, and, like I already said, chances are that we wouldn't end up skipping columns but in fact do some of them twice. This chance is in fact pretty much 1.

SMF spam blocked by CleanTalk