Sikuli interact with more than 1 matching object - sikuli

Hello so for example I have 4 balls that I must right click on, but when I right click them, nothing about the balls changes, how can I make it so that sikuli right clicks each of the balls and doesn't just get stuck on one of them?

You can use a for loop to search for all the balls.
Then in the for loop you can define what to do with it once found.
For example (Sikuli with Python):
Image_Balls = ()
for x in findAll(Image_Balls):
click(x)
Between the () you need to place a picture of how a ball looks like.
In this example he will find every ball on the screen and click on it.
You can also add a try, catch/exception in the for loop.
Then he will find every ball, and try to right click.
If the try failed, he will execute the catch (exception in python).
And will continue to look for the next ball, until there are no anymore.
Image_Balls = ()
for x in findAll(Image_Balls):
try:
rightClick(x)
except:
pass

Related

How to make a toggle type button in pygame?

I'm making a game with pygame, but I have a problem that button does not work as a toggle.
while True:
mousepos = pygame.mouse.get_pos()
mouseclk = pygame.mouse.get_pressed()
game.fill((0,0,0))
game.blit(cic, (0,0))
if mouseclk[0] and 1227 > mousepos[0] > 1120 and 485 > mousepos[1] > 413:
while True:
game.blit(pbut_rgm84, (1120,413))
pygame.mixer.music.load("sounds\se_beep.mp3")
pygame.mixer.music.play(0)
current_weaponinf = font.render(current_weapon[1], True, (255, 0, 0))
game.blit(current_weaponinf, (930,45))
else:
game.blit(but_rgm84, (1120,413))
This is my code for the button. As you know, If I click on that button, image of the button will be changed and sound will be played. But it will happen while i'm pressing on the button. So, I want to the button to be toggle type. Do you have any ideas on it?
EDIT 1: Sorry for the ramble. The answer is in the first part. The rest is just some notes on a more standard way to do what you asked for in PyGame. After all, the answer is not just for the OP, but everyone who visits this page.
EDIT 2: Notice also I had to change the code to lower down the FPS to 5 for this to work fine. The way you checked for a click meant that the mouse button was down for about 30 - 40 frames every click on my machine, hence resulting in 30 to 40 button toggles when only one was needed, so I had to lower down the FPS to 5 in the code. This is another reason why you might want to use the other method I described for event handling.
Answer:
I honestly appreciate the simple logic you used to check if the mouse click was in range of the object being pressed.
I could extend your code slightly to get the "toggle" type button you want (i.e, on a click, the image and sound changes. Click again, and the image and sound go back to normal).
However, I also would like to show you some better ways of dealing with mouse click events and click detection available in the Pygame module to improve your code. If you are interested and want to know what I mean, please read on after the code below. If you just wanna take the code and leave, I totally respect that (it's something I did a lot as well).
Here is your code modified to match your "toggle" button requirements (if I understood what you want to do right). Replace this with the part of your code you showed in your answer, but be aware that this may not work as I don't have your full code or the images / soundtracks you used :
toggle = False
pygame.mixer.music.load("sounds\se_beep.mp3")
pygame.mixer.music.play(-1)
pygame.mixer.music.pause()
clock = pygame.time.Clock()
while True:
mousepos = pygame.mouse.get_pos()
mouseclk = pygame.mouse.get_pressed()
game.fill((0, 0, 0))
game.blit(cic, (0, 0))
if mouseclk[0] and 1227 > mousepos[0] > 1120 and 485 > mousepos[1] > 413:
if toggle:
toggle = False
pygame.mixer.music.pause()
else:
toggle = True
pygame.mixer.music.unpause()
if toggle:
game.blit(pbut_rgm84, (1120, 413))
current_weaponinf = font.render(current_weapon[1], True, (255, 0, 0))
game.blit(current_weaponinf, (930,45))
else:
game.blit(but_rgm84, (1120,413))
clock.tick(5)
A Better Way: Handling Events
Handling mouse click events and in fact all other events is simple with what is called an event loop. Although there is a little bit more to it than this, for now we can say than an event loop checks for certain events triggered (such as key press, mouse click, quit game events) at every frame, and then triggers a callback function.
You already have one in your code! - At every loop in your while loop, you check if the mouse was clicked using mouseclk = pygame.mouse.get_pressed()
However this is incomplete and is not the standard way to implement event loops using the Pygame module. Here is how you do it (read the comment above each line to understand what it is doing) :
import pygame
from pygame.locals import *
...
# Main game loop - this is the while loop you have in your code. This is where frames are rendered on every new loop
while True:
#Get all event that have been triggered from the last frame
events = pygame.event.get()
# Now we go through each event separately
for event in events:
#Use an if statement to check what the event is. For example...
if event.type == MOUSEBUTTONDOWN: #If this event was a mouse button click
print("Clicked") #Do whatever function
elif event.type == QUIT: #If this event was quitting the game, i.e: pressing the X button on the game window
pygame.quit() #Close the game
#and so on. You can have as many elifs to check all the events you need
game.fill((0,0,0)) #... The rest of your code goes after the for loop (event loop)
So essentially in your main game loop (your while loop) you have inside it a for loop (the event loop), then after it back in the main while loop you have the rest of the code you need to run on every frame such as rendering images and animating sprites.
A Better Way: Rect Objects
You will find that to see if the mouse click position (x, y) was in range of the mouse button, you had to check if the mouse click's x value was in range of the X1 to X2 of the object you're clicking (top right and top left corners), and at the same time it also has to be in range Y1 to Y2 of the object (top right and bottom right corners), which effectively means the mouse was somewhere on the object when the mouse click event was triggered
For this, Pygame implements Rect objects. A rect can be explained as an imaginary rectangle with a width and height that you define when you create it ( I will show you how that is done in code below ). To be more realistic, it is a pygame object for storing rectangular co-ordinates (a range of all points within that rectangle).
Now the thing is that this rect object has methods like Rect.collidepoint, which will return True if the mouse click position is inside the rect. This is a more simplified, easier to understand way of detecting if a mouse click position is inside a rect or outside it.
So..
# Constructing a rect at position (0, 0) with width 100 and height 500
r = pygame.Rect(0, 0, 100, 50)
# Now lets assume that above there is code where a mouse click is detect and the position is stored in `mousepos`, where `mousepos[0]` is the X and `mousepos[1]` is the Y
# All we have to do now is tell pygame to check if this position is inside our Rect object *r* or not
if r.collidepoint(mousepos):
print("You clicked inside an imaginary box")
else:
print("You clicked outside my imaginary box")
# Simple!!!
Much easier and more readable! (especially after you remove the comments you will be dumbfounded by the simplicity of this (collidepoint means inside the rect).
In reality, this is not how you usually use rects, although it gives you the basic idea of what they are. Rects are used in a more object-oriented method where the button is a child class of the Pygame.sprite.Sprite class. Then you can assign a rect object as its self.image.rect property and use it from there. NOTE: this is not very detailed :D .
Also, this is not the only use of rects. You can check if one rect is inside another. You can check if a group of objects is inside a rect. You can even with only one line of code check whether one object of a group is inside a certain rect, and if so, remove it!
To understand more about how to code pygame from start to finish (as the extra part of this answer talking about events and rects is very incomplete and only there as a starting point), I would suggest this excellent yet very simple and easy to understand book. And all you need is a basic understanding of python syntax.

Jumping back and forth inside a Movieclip with a button?

So, I'm very much a beginner in AS3. I've been reading and figuring out things as I go, though I can't wrap my head around this.
So, I have 4 frames. Each frame has a different movie clip, MC1,MC2,MC3,MC4
Inside those four movie clips, there is another movie clip with the same instance name for each: BC, and inside that movie clip there are two frames. Frame 1 has a dot, and frame 2 does not.
MC1>BC>(2 frames)
MC2>BC>(2 frames)
and so on....
What I'm trying to do: I wanted to see if there was any way to control the frame navigation of BC inside all four MC clips at the same time with one button.
I want to switch back and fourth between the two frames inside the BC movie clip.
I'm at a loss, I've tried quite a few things.
You should be able to do so by giving them all the same instance name (so long as there is only ever one of them on screen at once).
So lets say you have a button that spans all 4 frames with an instance name of navBtn and you gave each of the MC1-4 clips the same instance name of MC. You could do the following on frame 1:
navBtn.addEventListener(MouseEvent.CLICK, navBtnClick);
function navBtnClick(e:Event):void {
if(MC.BC.currentFrame == 2){
MC.BC.gotoAndStop(1);
}else{
MC.BC.gotoAndStop(2);
}
}
Reading your question again, perhaps what are looking for is to have each clip automatically go to the same frame for their BC child when they load? If that is the case, then follow the example in the comment on your question by #Organis. Here is one way you could accomplish this:
Create two variable on frame one of your main timeline:
var BC_NAV_CHANGE:String = "BC_NAV_CHANGE";
var BC_CurFrame:int = 1;
Then, when you need to change the frame of the BC objects, do the following:
//create a function that you call when you want to change the BC frame
function toggleBCFrame(e:Event = null){
MovieClip(root).BC_CurFrame = MovieClip(root).BC_CurFrame == 1 ? 2 : 1;
//the line above is a if/else shorthand, that is setting a new value to the `BC_CurFrame` var,
//if the current value is `1`, it will set it to `2`, otherwise it will set it to `1`
MovieClip(root).dispatchEvent(new Event(MovieClip(root).BC_NAV_CHANGE));
//this line (above) dispatches a event telling anything that's listening that the variable has changed
}
If the code above is on the main timeline, you can forgo all the MovieClip(root). parts of the code.
Now, on the timeline of your BC MovieClip(s), put the following code:
//create a function that goes to and stops at the frame stored in the global variable
function updateFrame(e:Event = null){
gotoAndStop(MovieClip(root).BC_CurFrame);
}
//next listen for the BC_NAV_CHANGE event, and call the above update function above any time that event happens
MovieClip(root).addEventListener(MovieClip(root).BC_NAV_CHANGE, updateFrame);
//lastly, call the update function right away so when the BC clips loads it immediately goes to the correct frame
updateFrame();

as3 hittestobject not working, dont understand why

the collision not working i cant understand why, i put collision movieclips in the object and it doesnt seem to recognise one of the but does with the other, sorry for the confusing way of stating the problem if you play the game you will understand. im open to changing the way collision works too as long as it works ill be super happy
I'll try to explain. When You click "Down" or "Up" hero (box_MC) collide with both doors "Top_Door" and "Bottom_Door". Inside "bang" function at first checking collision with "Bottom_Door", so, hero always go down (.y += 100) and second condition (Top_Door) never will be true. How to fix this? Add variable var lastAction:String;. This variable will store last action: "up" or "down". Inside "down_MC_P" function initialize this variable by "down". Inside "up_MC_P" — "up". Next, replace the first condition to this if (box_MC.hitTestObject(cycle[i].Bottom_Door) && lastAction == "down") and second: if(box_MC.hitTestObject(cycle[i].Top_Door) && lastAction == "up"). That's all.

Receiving click events from separate lines with AS3

I want to receive separate click events from separate lines in a text field, and every time a certain line is clicked by the user, I would like to highlight it and have an event happen.
I would ideally like this to happen with dynamic text, and not have to break the text apart by hand. Using the htmlText property is an option, but I am unsure as to how to bind clickEvents to separate elements.
Where do I begin?
There is no ready to use solution for this. But you can make it yourself using a few things:
set CLICK listener for the whole text field
listen for click and check the caretIndex property
use getLineIndexOfChar to check what's the line of the current caret position
use getLineOffset and getLineLength to get the position of the first and last character of that line
use setSelection to highlight this line
There might be some faster and easier way, but this is what works for sure :)
EDIT: decided to post the solution code, as I was wondering how exactly it works.. and it would be a shame to just leave it unpublished and make you do it instead :)
field.addEventListener(MouseEvent.CLICK, onTfClicked);
function onTfClicked(e:MouseEvent):void {
trace (field.caretIndex);
var line:uint = field.getLineIndexOfChar(field.caretIndex);
var start:uint = field.getLineOffset(line);
var end:uint = start + field.getLineLength(line);
field.setSelection(start, end);
}

Connecting two handles in Matlab

I would like to connect my two axes.handles so that when the mouse button is clicked on one, the other one would also do what the first one do. I have an external function that executes out what I want to do when the mouse is clicked. I just need to update the two handles in GUI so that it will do the same thing when one axes is clicked.
In Main GUI
function testminiproj_OpeningFcn(hObject, ~, handles, varargin)
handles.output = hObject;
handles.done=0;
guidata(hObject, handles);
setappdata(0,'figureHandle',gcf);
setappdata(gcf,'axesHandle1',handles.axes6);
setappdata(gcf,'axesHandle2',handles.axes7);
And this is my external function which is callback into main GUI by calling mousemotion;
function varargout = mousemotion(this,varargin)
%// get the figure handle from the application main data
figureHandle = getappdata(0,'figureHandle');
%// get the axes handle from the figure data
axesHandle1 = getappdata(figureHandle,'axesHandle1');
%// get the axes handle from the figure data
axesHandle2 = getappdata(figureHandle,'axesHandle2');
global rdata;
if nargin<1
set(gcf,'WindowButtonDownFcn','mousemotion(''down'')');
set(gcf,'WindowButtonUpFcn','mousemotion(''up'')');
set(gcf,'WindowButtonMotionFcn','');
Appreciate any help. I am bad at trying to put the question across. Hope someone could help. Thanks.
You can make a handles vector. Like this:
axesHandles = [axesHandles1; axesHandles2];
set(axesHandles, 'PropertyName', PropertyValue);
This way both axes' property values will be set to PropertyValue.
You need to work around and manually find out which axes is clicked in.
It's actually not hard.
Just use the Position attribute of the figure and axes.