If it Can't Find, Closes Early

Asked by Lisa Howells

I'm trying to make something simple for a game macro. sometimes a button randomly appears in intervals between 5 and 500 seconds. I want it to detect and click the button within 10 seconds, but to not click if the button doesn't exist. Yet if I try something like:

while has(randomButtonImage):
    click(randomButtonImage)

If the button isn't already up, the program closes saying findfailed. if the button is up and I run the program, it goes to the button, clicks it a few times(even after it has disappeared), and then when the button is gone from being clicked the program terminates because it says findfailed.

I'm confused because sikuli says it doesn't throw a findfailed for has() in version 1.1.4.

All I want it to do is click the button once when it exists (and then the button in the game goes away for 5-500 seconds), and then to keep searching for the button until it comes up again (but not clicking unless it exists, and to stop terminating from findfailed if the image doesn't exist).

Thanks for any help.

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Solved by:
RaiMan
Solved:
Last query:
Last reply:
Revision history for this message
masuo (masuo-ohara) said :
#1

As a standard behavior Sikuli internally processes about 3 search operations per second.
So if "image.png" has existed before about 300 milseconds, has("image.png") return true.
https://sikulix-2014.readthedocs.io/en/latest/scripting.html#Settings.ObserveScanRate

Revision history for this message
Lisa Howells (lisa-1993) said :
#2

but why does it say findfailed when I'm using
while has(image)

as soon as the image goes away? I want it to keep searching for the image until it comes up again to click it agian.

Revision history for this message
masuo (masuo-ohara) said :
#3

Are there FindFaile error messages?

Revision history for this message
Lisa Howells (lisa-1993) said :
#5

[error] Error caused by: Traceback (most recent call last): File "C:\Users\Lisa\Documents.sikuli\ClickButton.py", line 6, in <module> click("randomButton.png") Line 2275, in file Region.java
at org.sikuli.script.Region.wait(Region.java:2275)
at org.sikuli.script.Region.wait(Region.java:2293)
at org.sikuli.script.Region.getLocationFromTarget(Region.java:3302)
at org.sikuli.script.Region.click(Region.java:3907)
at org.sikuli.script.Region.click(Region.java:3892)
at sun.reflect.GeneratedMethodAccessor24.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
org.sikuli.script.FindFailed: FindFailed: randomButton.png: (57x27) seen at (1313, 540) with 0.75 in R[0,0 1680x1050]@S(0) Line 2275, in file Region.java

this happens once the button has been found and clicked and gone away so there's no button on the screen until it randomly comes back in a few minutes. I want the program to not stop, but to keep looking for when the button appears again but this error happens instead.

Revision history for this message
masuo (masuo-ohara) said :
#6

try this.

while has(randomButtonImage):
    click(randomButtonImage)
    sleep(1)

Revision history for this message
Best RaiMan (raimund-hocke) said :
#7

while True:
    If has(Image):
        click() # clicks last match
        waitVanish(Image)
    wait(1)

This will forever click the image when it comes up and then wait until the image vanishes

Revision history for this message
Lisa Howells (lisa-1993) said :
#8

Tried your exact 3 line script. I ran it 4 times, it did the same thing all 4 times, the program clicks the button (then the button goes away) and then it clicks where the button was a couple times and then the program closes (and then the sikuli IDE opens up again). it only gave this error message on the fourth try though. first 3 tries had no error message.

[error] script [ testScript ] stopped with error at line --unknown--
[error] Error caused by: Traceback (most recent call last): File "C:\Users\Lisa\Documents.sikuli\TestScript.sikuli\TestScript.py", line 2, in <module> click("randomButton.png") Line 2275, in file Region.java
at org.sikuli.script.Region.wait(Region.java:2275)
at org.sikuli.script.Region.wait(Region.java:2293)
at org.sikuli.script.Region.getLocationFromTarget(Region.java:3302)
at org.sikuli.script.Region.click(Region.java:3907)
at org.sikuli.script.Region.click(Region.java:3892)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
org.sikuli.script.FindFailed: FindFailed: randomButton.png: (58x65) seen at (777, 625) with 0.79 in R[0,0 1680x1050]@S(0) Line 2275, in file Region.java

Revision history for this message
Lisa Howells (lisa-1993) said :
#9

Thanks RaiMan, that solved my question.

Revision history for this message
Lisa Howells (lisa-1993) said :
#10

RaiMan thank you so much I had been trying to get this to work for a while! I have one last question. Why does Masou's 3 line script example not work and it terminates and then gives that error? I want to learn why so I don't make mistakes like that in the future.

Revision history for this message
RaiMan (raimund-hocke) said :
#11

You have to fully understand, how SikuliX internally works.

This might be helpful:
https://sikulix-2014.readthedocs.io/en/latest/basicinfo.html#sikulix-how-does-it-find-images-on-the-screen

... so it is all about timing.

When searching an image on the whole screen, a search op might take up to 500 msec, which then is repeated until found or wait time is elapsed (FindFailed exception).

So for critical parts of your workflow or GUI's that change without being acted on, you have to adjust your search timing.

This should generally be avoided:
if has(image):
   click(image)

.... if it comes to the click op, then the image was already found some milli-seconds before.
but saying click(image) will start a new search, which at least costs some 10 msecs and might lead to FindFailed in fast changing GUI situations.

so either say:
if has(image):
   click()

which is short for:
if has(image):
   click(getLastMatch())

another option is to use:
click(wait(image, waitTime))

which will either click (meaning found) or throw a FindFailed.

In the end, you have to find your own way based on the knowledge of how SikuliX works and about the timing of your automated GUI.