Identifying clickable object behind a non-clickable overlaying object [resolved]

Started by WHAM, Thu 04/08/2011 19:46:47

Previous topic - Next topic

WHAM

I'm trying to make a script which changes the mouse cursor when the mouse is over an object or a hotspot. However, in most of my rooms I have overlaying transparent objects, which have their clickable attribute set to false, however, the below script still picks them up, causing the check to fail on objects which are behind the overlaying transparent ones-.

So far I haven't had luck in finding a way to get the script to ignore non-clickable objects. Even if I add a chech that stops the cursor from changing if the object is not clickable, but that doesn't really solve the problem.

Code: ags

  if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) != hotspot[0]) {
    mouse.UseModeGraphic(eModeUsermode1); // This works just fine
  } else if (Object.GetAtScreenXY(mouse.x, mouse.y) != object[0]) {
    mouse.UseModeGraphic(eModeUsermode1);
  }


Any good ideas on how this could be done in AGS?
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

Khris

I have just tested all three methods:

1. @OVERHOTSPOT@
2. Object.GetAtScreenXY
3. GetLocationType

In every case, the non-clickable semi-transparent object (ID 1) overlaying the clickable object (ID 0) is ignored just fine, everything works as expected.

About your code: the first object in a room is object[0] so the check should use null.
Same with characters btw, only for hotspots, hotspot[0] represents nothing.

My only explanation for your result is that your clickable object is in fact object 0. Just add another clickable object and even your faulty code should work for that one.

WHAM

I guess that was my failure then. I hadn't noticed the characters and objects start from ID "0", unlike hotspots. I ended up using this:

Code: ags

  if (GetLocationType(mouse.x, mouse.y) == eLocationHotspot) {
    mouse.UseModeGraphic(eModeUsermode1);
  }  else if (GetLocationType(mouse.x, mouse.y) == eLocationObject) {
    mouse.UseModeGraphic(eModeUsermode1);
  }  else if (GetLocationType(mouse.x, mouse.y) == eLocationCharacter) {
    mouse.UseModeGraphic(eModeUsermode1);
  }  else {
    mouse.UseDefaultGraphic();
  }


Thanks again, Khris!
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

monkey0506

You should not call functions like GetLocationType or XXX.GetAtScreenXY multiple times repeatedly like that. You should store the results once in a variable or pointer:

Code: ags
  LocationType loctype = GetLocationType(mouse.x, mouse.y);


However, that's not your biggest problem here. Right now you're doing the same thing for every value of LocationType except eLocationNothing. This is the same as what you've written:

Code: ags
  if (GetLocationType(mouse.x, mouse.y) != eLocationNothing) mouse.UseModeGraphic(eModeUsermode1);
  else mouse.UseDefaultGraphic();

WHAM

Out of curiosity: is there a specific reason why they should not be called repeatedly like that? Or is is just a meaningless "resource hog" which your latter example can easily solve.

I'm not at my home right now, so I cannot test, but if I set it to change the cursor on everything BUT eLocationNothing, won't it recognize regions and such, or will it just restrict to hotspots, characters and objects?
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

monkey0506

Yes, there is a specific reason they should not be called repeatedly in that fashion. When you're calling the functions, it's not just the same as checking the value of a single variable. The engine has to process what is displayed on the screen, and then compare the given coordinates against that, which could involve having to process alpha channels, AGS transparency, etc. which isn't necessarily slow, but the matter comes down to why would you want to force the engine to redo all of that work several times?

Storing the result in a variable means the engine has to process the requested information once, and then you can just check the result as needed. The way you were doing it, you're having to process the whole thing every time.

Regarding your second question, first let me say that the player can't even interact with regions in that fashion. They can walk onto them, off of them, stand on them, and you can check for their existence, but GetLocationType only deals with items that can be interacted with. Secondly, the possible values for the LocationType enum are eLocationCharacter, eLocationHotspot, eLocationObject, and eLocationNothing. Those are the only values that will be returned by GetLocationType. GUIs, InventoryItems, and hotspot 0 are all treated by this function as eLocationNothing. But since you were checking every value except eLocationNothing and doing the same thing, then the two code snippets are exactly equivalent. That's simply logic.

Oh, and I wanted to add that hotspot IDs do not in fact start from 1, they start from 0. The only items I'm aware of in AGS that have indices starting from 1 are Views and InventoryItems. hotspot[0] is a valid Hotspot*. It has all of the same functionality as a normal hotspot. You can add event functions, give it a name, etc., and it's all still valid. The engine does make an exception (for functions like GetLocationType and for @OVERHOTSPOT@) in order to treat hotspot[0] as "nothing" by default, but you could forcibly override that if you choose to do so, and use it exactly as you would any other hotspot. Why you might want to do that is entirely up to you, but I wanted to point out that they are indeed indexed from 0 and not 1.

WHAM

Huge thanks for clearing that up Monkey! I've been a bit lazy with ensuring my code doesnt do anything unnecessary as long as I haven't had any noticeable slowdown with my games. Thus I've been stuffing things in repeatedly execute always with wild abandon in my previous projects.

Now that I think of it, I should probably clean those up and reorganize the functions a little better, just to be safe. Maybe add some "if" checks around stuff that only need to be checked in certain rooms etc, so that the checks arent run carelessly in all rooms.
Wrongthinker and anticitizen one. Utterly untrustworthy. Pending removal to memory hole.

SMF spam blocked by CleanTalk