Checking Co-ords

Started by Atelier, Tue 10/07/2012 22:31:53

Previous topic - Next topic

Atelier

Hi guys, this is pretty basic but my brain is frazzled. I'm checking whether the mouse is over a certain coordinate.

The units in my game have an x and y coordinate and the sprite is 27x27 with the coordinate in the middle (so the sprite is drawn at x-13, y-13).

Code: AGS

function room_RepExec()
{
     while (u <= total*2) // total allied units, x2 for enemy units
     {
          if ((unit[u].x-13) < mouse.x < (unit[u].x+13)) {
          if ((unit[u].y-13) < mouse.y < (unit[u].y+13)) {

               // do stuff

          } }

     u++;

     if (total*2 < u) u = 1;
     }
}


I think the co-ord checking bit would work in theory?

But obviously, the game just crashes because I cycle through all the units constantly, but I can't check the coordinates if I don't do that, and noloopcheck locks the game up. How else could I do it?

Cheers
Atelier

Khris

You can't combine two < tests like that, you need to do
Code: ags
if (unit[u].x-13 <= mouse.x && mouse.x <= unit[u].x+13)

(Note: <=, not <, otherwise you're only handling 25 of 27 pixels)
As yours did compile, I guess AGS turns one side into true/false, then evaluates that as 1/0.

Re crash: Why are you resetting u to 1 right when the loop is supposed to end? No wonder AGS hangs, since you've deliberately created an endless loop. All u are checked in the very next frame again anyway. Just remove the last if line. Instead, call u = 1; right before the loop.

Btw, if your game is tile-based, you're better off with tile coordinates. Basically, mouse-coordinates are turned into tile coordinates, then all game handling is done, then tile coords are turned back into screen coords for graphic output.
I'd also add a map array that stores the current unit occupying each tile, to avoid having to iterate through all units each loop.

Atelier

#2
Thanks Khris, it works now.

But something strange happens - when the mouse hovers over units a GUI should appear... this only happens to the enemy units though. Basically the player selects how many of each unit they want, this becomes int total, and the same amount of [randomised] units becomes AI. So total*2 should equal the last used slot in the unit array. But for some reason the while loop only checks the last half (ok, it's probably not a fault in the while loop, but it doesn't make sense, because I check the value of total*2 just before and there's no reason why it shouldn't cycle through just the last half).

Code: AGS

function room_RepExec()
{
     int u = 1;

     while (u <= total*2)
     {
          //check coords
     
          u++;
     }

}


Is it something wrong with the loop, or is the problem how the units are defined in the first place?

Edit: It's worth mentioning that

Code: AGS

while (u <= total)


does show the first half of total*2, because naturally the loop doesn't extend to the other half of the units (enemy units). Only when total is multiplied by 2 does the first half of the units not show on mouseover...

Edit 2:

Ok, another problem...

Doing

Code: AGS

if (unit[u].x-13 <= mouse.x && mouse.x <= unit[u].x+13) {
if (unit[u].y-13 <= mouse.y && mouse.y <= unit[u].y+13) {
 //
}}


causes it to check that the mouse is within the x boundary properly, but if you move the mouse up and down within that, the GUI remains until you hover over another unit, even if you are way more than 13 pixels vertically from the first one. This only happens when you don't multiply total by 2 for the condition of the while loop. If you do, it works fine, but only on the enemy units (last half), so the first problem applies again. I did this:

Code: AGS

if ((unit[u].x-13 <= mouse.x && mouse.x <= unit[u].x+13) && (unit[u].y-13 <= mouse.x && mouse.x <= unit[u].x+13))


and this works as intended, but only when you hover over the last unit to be defined!

I'm thinking of changing it to tile-based to avoid these problems, even though I really wanted an "open" movement system and I present the game in four days...

Atelier

Does anybody know why the while loop isn't functioning properly? It's really frustrating :-\

Khris

The while loop looks fine.
This though:
Code: ags
if ((unit[u].x-13 <= mouse.x && mouse.x <= unit[u].x+13) && (unit[u].y-13 <= mouse.x && mouse.x <= unit[u].x+13))

has a few typos, the last three .x are supposed to be .y.

And until we know what code actually is inside the while loop, we can't really help with your GUI question.

Atelier

#5
Code: AGS

DrawingSurface*surface;
DynamicSprite*sprite, overlay, final;
//sprite.Graphic is the background sprite with all the units drawn on top

function repeatedly_execute() 
{
     if (player.Room == 1) {
          
     int u = 1;
     
     while (u <= total*2)
     {
         
         if (((unit[u].x-13 <= mouse.x) && (mouse.x <= unit[u].x+13)) && ((unit[u].y-13 <= mouse.y) && (mouse.y <= unit[u].y+13))) {

               overlay = DynamicSprite.Create(800, 600, true);
               final = DynamicSprite.CreateFromExistingSprite(sprite.Graphic);

               surface = overlay.GetDrawingSurface();
               int slot;
               if (unit[u].type == eUnionInfantry) slot = 30;
               else if (unit[u].type == eUnionCavalry) slot = 29;
               else if (unit[u].type == eUnionArtillery) slot = 28;
               else if (unit[u].type == eConfInfantry) slot = 25;
               else if (unit[u].type == eConfCavalry) slot = 24;
               else if (unit[u].type == eConfArtillery) slot = 8;
                    
               if (unit[u].plyr) surface.DrawingColor = 10; else surface.DrawingColor = 12;
               int first, second; // make sure the smallest circle is always drawn last
               if (unit[u].mvm < unit[u].rng) { first = unit[u].rng; second = unit[u].mvm; }
               else if (unit[u].rng < unit[u].mvm) { first = unit[u].mvm; second = unit[u].rng; }
               
               surface.DrawCircle(unit[u].x, unit[u].y, first);
               if (unit[u].plyr) surface.DrawingColor = 2; else surface.DrawingColor = 4;
               surface.DrawCircle(unit[u].x, unit[u].y, second);
               surface.DrawImage(unit[u].x-1-(Game.SpriteWidth[slot]/2), unit[u].y-1-(Game.SpriteHeight[slot]/2), slot);
               
               surface = final.GetDrawingSurface();
               surface.DrawImage(0, 0, overlay.Graphic, 60);
               
               surface.Release();               
               gBattlefield.BackgroundGraphic = final.Graphic;
               
               if (unit[u].type == eUnionInfantry) infoType.Text = "Unionist Infantry";
               else if (unit[u].type == eUnionCavalry) infoType.Text = "Unionist Cavalry";
               else if (unit[u].type == eUnionArtillery) infoType.Text = "Unionist Artillery";
               else if (unit[u].type == eConfInfantry) infoType.Text = "Confederate Infantry";
               else if (unit[u].type == eConfCavalry) infoType.Text = "Confederate Cavalry";
               else if (unit[u].type == eConfArtillery) infoType.Text = "Confederate Artillery";
               
               infoWeapon.Text = unit[u].weapon;
               infoStats.Text = String.Format("Dam: %d Mvm: %d Rng: %d Def: %d", unit[u].dam, unit[u].mvm, unit[u].rng, unit[u].def);
               
               if (unit[u].plyr) infoType.TextColor = 10;
               else infoType.TextColor = 12;
               
               int width = GetTextWidth(infoType.Text, infoType.Font);
               if (width < GetTextWidth(infoWeapon.Text, infoWeapon.Font)) width = GetTextWidth(infoWeapon.Text, infoWeapon.Font);
               if (width < GetTextWidth(infoStats.Text, infoStats.Font)) width = GetTextWidth(infoStats.Text, infoStats.Font);
               
               infoType.Width = width+12; infoWeapon.Width = width+12;
               infoStats.Width = width+12; gInfo.Width = width+12;
          
               int x = mouse.x+2, y = mouse.y+2;
               if (800-gInfo.Width < x) x = 800-gInfo.Width-5;
               if (600-gInfo.Height < y) y = 600-gInfo.Height-5;
               gInfo.SetPosition(x, y);
               
               gInfo.Visible = true;
          }

          else // mouse not over a unit, so change to background sprite
          {
               gInfo.Visible = false;
               gBattlefield.BackgroundGraphic = sprite.Graphic;
          }
          

     u++;
     
     }
     
     
  }
}


Sorry, here's the full code (copied and pasted this time, not translated manually to avoid all my typos ;))

Like I say, the GUI only shows up and circles are only drawn if the mouse is over the last unit in the array, which is always an enemy unit.

Crimson Wizard

#6
This is pretty obvious.
What you do is create a gui for selected unit, then CONTINUE going through the loop. As soon as next iteration starts, the condition fails, and gui is hidden.
You need to break from the loop right after you created the gui.

For example:
Code: ags

bool found = false;

while (!found && u <= total*2)
{
   if (((unit[u].x-13 <= mouse.x) && (mouse.x <= unit[u].x+13)) && ((unit[u].y-13 <= mouse.y) && (mouse.y <= unit[u].y+13))) {
      found = true;
      ....

Atelier

Thanks Crimson, I knew it would be embarrassingly simple :)

SMF spam blocked by CleanTalk