How to examine a hotspot when close enough?

Started by , Tue 26/09/2006 23:19:33

Previous topic - Next topic

Redbeard

Hi folks, I've hit a brick wall with my game design. What I'm trying to do is create a script that will allow me to examine a hotspot only if i am close enough to it. I have tried the "set walk-to point" but when the action takes place, it causes my gui images to flicker horribly. So, I would like to write a function that would check to see if my character's location is close enough to the hotspot before the interaction takes place. I have spent a few hours researching the manual and the forums but I can't find the solution yet. The syntax would be similar to something like this:

if (player location is near hotspot)
gui image = you examine the hotspot;
else gui image = you need to get closer to examine the hotspot;

The problem I havent figured out is how to compare a hotspot location to a player/character location. Here is a code snippet I am trying to modify in the process:

Button *theButton2 = gExamine.Controls[0].AsButton;
if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) == hLamp1)
   {theButton2.NormalGraphic = 149;}Ã, 

Any help would be appreciated. Thanks!!

Redbeard

Khris

In the global script, add this to the beginning, outside any function:
int distance(int x1, int y1, int x2, int y2) {
Ã,  x1=x1-x2;
Ã,  x1=x1*x1;
Ã,  y1=y1-y2;
Ã,  y1=y1*y1;
Ã,  return FloatToInt(Maths.Sqrt(IntToFloat(x1+y1)));
}

Then go to the on_mouse_click function and look where it says
Ã,  if (button==eMouseLeft) {
Ã,  Ã,  ProcessClick(mouse.x, mouse.y, mouse.Mode);
Ã,  }

Change that to the following:
Ã,  int x=mouse.x;
Ã,  int y=mouse.y;
Ã,  int hx;
Ã,  int hy;
Ã,  if (button==eMouseLeft) {
Ã,  Ã,  if (GetLocationType(x, y)!=eLocationHotspot) ProcessClick(mouse.x, mouse.y, mouse.Mode);
Ã, Ã,  Ã, else {Ã,  // special hotspot handling
Ã,  Ã, Ã,  Ã, Hotspot*h=Hotspot.GetAtScreenXY(x,y);
Ã,  Ã,  Ã,  hx=h.WalkToX;
Ã, Ã,  Ã, Ã,  hy=h.WalkToY;
Ã,  Ã, Ã,  Ã, if (distance(player.x, player.y, hx, hy)<40) {Ã,  // adjust 40
Ã,  Ã,  Ã, Ã,  Ã, // button code "you examine/interact"
Ã,  Ã,  Ã,  Ã,  h.RunInteraction(mouse.Mode);
Ã, Ã,  Ã, Ã,  }
Ã,  Ã, Ã,  Ã, else {
Ã,  Ã,  Ã,  Ã,  // button code "you need to get closer"
Ã, Ã,  Ã, Ã,  }
Ã, Ã,  Ã, }
Ã,  }

Fornax

Thanks KhrisMUC,

I'm trying to do something similar so your solution was a welcome find.

However, it works with the hotspot's WalkToPoint, doesn't it?

What if you had a really long hotspot, like a hedge or a wall and you wanted the player to be able to interact with the wall provided they were within 1 metre of it ANYWHERE along its length?

Is there some way to detect the distance between the player and the NEAREST point in a hotspot's area?

Or would that be an AGS enhancement request?

Ashen

#3
There's no direct way to do that (as in, an in-built command), so it'd have to be a suggestion - and I don't know how high priority it'd be to introduce.

It should be possble to make a function of your own to figure it out, though. I'm about to go to bed and can't figure the maths out, but I'm sure someone can come up with it for you. You'd need to use variables to move out from the Player's coordinates until you hit the Hotspot, then figure out the distance between them using something like Khris' code above. I think that'd be it, anyway.
I know what you're thinking ... Don't think that.

Alynn

Or why not just create yourself a region and if the character is on that region set a variable, when they walk off unset the variable

Player Walks off region
isOnRegion = true;

Player Walks off region
isOnRegion = false;


Then in the interaction

if (isOnRegion) {
//I'm close enough to see stuff code.
}
else {
// I'm not close enough to see stuff code.
}

Kweepa

#5
If you want to do it without regions:

Code: ags

bool IsHotspotInRange(Hotspot *hot, int x, int y, int range)
{
   int minX = x - range;
   int maxX = x + range;
   int rangeSquared = range*range;

   int loopX = minX;
   while (loopX <= maxX)
   {
      int xSideSquared = (loopX - x)*(loopX - x);
      // this simplifies the inner loop, which makes the test faster
      int yRange = FloatToInt(Math::Sqrt(IntToFloat(rangeSquared - xSideSquared)));
      int minY = y - yRange;
      int maxY = y + yRange;
      int loopY = minY;
      while (loopY <= maxY)
      {
         if (Hotspot.GetAtXY(loopX, loopY) == hot)
         {
            return true;
         }
         loopY++;
      }
      loopX++;
   }
   return false;
}

// usage
if (IsHotspotInRange(cPlayer.GetX(), cPlayer.GetY() - 20, 16, hLamp1))
{
   ...
}


NB: This is prohibitively expensive for ranges over about 40 pixels.

EDIT: Simplified inner loop
Still waiting for Purity of the Surf II

Fornax

#6
Quote from: Alynn on Fri 19/01/2007 02:47:43
Or why not just create yourself a region and if the character is on that region..

A clever solution! Hmm.. a few problems, though: what if you needed regions for lighting? what if two hotspots were close together? You'd need a region in between which could service both? And there's the extra work to make all the regions, for every hotspot, in every room. It would work, but under very controlled circumstances. I really do need the regions for lighting.

I think SteveMcCrea's solution would work better for the game I'm making. It's dynamic. If hotspots change you wouldn't have to do anything else to make it work.
Also, you could boost the performance by incrementing by 2 (loopX += 2) or even 3. Hotspots shouldn't be so small that 1 pixel would make any difference.

Thanks, guys.

SMF spam blocked by CleanTalk