How to write it
game.clicked()
It takes nothing. It gives back True once for each new click on the game window, then False until the player clicks again. One click, one action.
It comes with a few mouse friends:
- game.mouse_x(), game.mouse_y()
- Where the mouse pointer is, in game coordinates, the same ones your sprites use.
(0, 0)is the top-left corner. - sprite.at_mouse()
Truewhile the pointer is over that sprite (inside its collision box).- game.mouse_down()
Truethe whole time the mouse button is held down, every frame. Likegame.pressed(), but for the mouse.- game.mouse_in()
Truewhile the pointer is over the game window.
A full example
Balloons float up. Aim with the mouse and click a balloon to pop it:
import game
import random
game.window(480, 360, background="#87ceeb")
game.hide_cursor() # the target is the pointer now
aim = game.sprite("🎯", 240, 180, size=30)
aim.layer = 500 # in front of the balloons
board = game.label("Popped: 0", 80, 24, color="#ffffff", background="#1d4ed8")
balloons = []
for i in range(5):
balloon = game.sprite("🎈", random.randint(40, 440), random.randint(380, 700), size=50)
balloons.append(balloon)
popped = 0
while game.playing():
aim.x = game.mouse_x()
aim.y = game.mouse_y()
click = game.clicked() # ask ONCE per frame
for balloon in balloons:
balloon.y = balloon.y - 2
if click and balloon.at_mouse():
popped = popped + 1
board.content = "Popped: " + str(popped)
game.sound("hit")
click = False # one click pops one balloon
balloon.y = 400 # send it back to the bottom
if balloon.y < -30:
balloon.x = random.randint(40, 440)
balloon.y = 400
game.frame()
Clicking a sprite is always the same two checks together: is the pointer over it (balloon.at_mouse()), and was there a click (game.clicked())? Both True means "the player clicked this balloon".
One click, or holding the button?
Pick the one that matches what the player should do:
game.clicked()is for one click, one action: pop one balloon, pick one card, fire one shot. Holding the button down still counts as just one click.game.mouse_down()isTrueon every frame while the button is held. Use it for things that keep going: painting, a machine gun, charging up a jump.
import game
game.window(480, 360, background="#ffffff")
while game.playing():
if game.mouse_down(): # hold to paint
game.plot(game.mouse_x(), game.mouse_y(), "#e11d48", size=6)
game.frame()
Use game.mouse_down() to pop balloons and one long press would pop every balloon the pointer drifts over. Use game.clicked() to paint and you'd only get one dot per click.
Good to know
- Taps count. On a phone or tablet, a tap is a click, and the finger's position is the mouse position.
- Only clicks on the game window count. Clicking the code or the Output panel does nothing.
- Clicks on a game.button() count too, because the button sits on top of the game window.
at_mouse()uses the collision box, the same one touches() uses. Turn ongame.debug(True)to see the red box you have to click inside.- A sprite as the pointer.
game.hide_cursor()hides the real arrow, then move a sprite togame.mouse_x(),game.mouse_y()every frame, like the target above.
Why isn't my click working?
- Only the first sprite in my list ever gets clicked. You wrote
if game.clicked() and balloon.at_mouse():inside theforloop. The firstgame.clicked()uses up the click, so every balloon after it seesFalse. Askclick = game.clicked()once, before the loop, and checkclickinside it, like the example. - Only one of my two click checks ever works. Two different
ifs each callgame.clicked()? Only the first one gets the click. Save it in a variable once per frame and use that. - One click pops a whole stack of balloons. Set
click = Falseafter the first one is popped, so the rest don't count it. - It does way too much while I hold the button. You used
game.mouse_down(). Swap togame.clicked()for one action per click. - I have to click right in the middle. The collision box is a bit smaller than the picture. Check it with
game.debug(True), and make it bigger withsprite.hitbox = (width, height). A longgame.label()only has a small box in its middle, so for a clickable word use a game.button() instead. - It isn't checked every frame.
game.clicked()has to be asked inside thewhile game.playing():loop, which ends withgame.frame(). Asked once at the top of the program, it's almost alwaysFalse.