storing Mousebutton events in Pygame - python

Is it possible to click with the mouse on to different rectangle buttons in Pygame,getting the x-y position and make an if statement with them as variables.
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
.
.
.
if button_cliked_one and button_cliked_two:
print ('buttons clicked')
else:
print('something is wrong')

It is hard to understand what you want, but maybe you want to store previous mouse clicking positions in order to draw rectangles?
All you have to do is to store then in a different variable. If you want just two click positions at a time, you just use that. Or you can use a Python list to store the positions of an arbitrary number of clicks.
import pygame, sys
SIZE = 640, 480
screen = pygame.display.set_mode(SIZE)
# empty list
all_clicks = []
drawn = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# store mouse click position in the list:
all_clicks.append(event.pos)
# event.pos already has the info you'd get by calling pygame.mouse.get_pos()
drawn = False
print(all_clicks)
# at every second click:
if not len(all_clicks) % 2 and not drawn:
# draw a rectangle having the click positions as coordinates:
# pick the minimal x coordinate of both clicks as left position for rect:
x = min(all_clicks[-1][0], all_clicks[-2][0])
# ditto for top positionn
y = min(all_clicks[-1][1], all_clicks[-2][1])
# and calculate width and height in the same way
w = max(all_clicks[-1][0], all_clicks[-2][0]) - x
h = max(all_clicks[-1][1], all_clicks[-2][1]) - y
pygame.draw.rect(screen, (255, 255, 255), (x, y, w, h))
drawn = True
# update screen:
pygame.display.flip()
# pause a while (30ms) least our game use 100% cpu for nothing:
pygame.time.wait(30)

You can use variables previous_button and current_button to remeber two last buttons. And then you can check if they are correct.
It is similar to #jsbueno solution but I use two variables, not list.
If you want check longer combinations then you can use list.
import pygame
# --- functions ---
def check_which_button_was_click(buttons, pos):
for name, (rect, color) in buttons.items():
if rect.collidepoint(pos):
return name
# --- main ---
# - init -
screen = pygame.display.set_mode((350, 150))
# - objects -
buttons = {
'RED': (pygame.Rect(50, 50, 50, 50), (255, 0, 0)),
'GREEN': (pygame.Rect(150, 50, 50, 50), (0, 255, 0)),
'BLUE': (pygame.Rect(250, 50, 50, 50), (0, 0, 255)),
}
previous_button = None
current_button = None
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - event -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
clicked_button = check_which_button_was_click(buttons, event.pos)
if clicked_button is not None:
previous_button = current_button
current_button = clicked_button
print(previous_button, current_button)
# - updates -
if previous_button == 'RED' and current_button == 'BLUE':
print('correct buttons clicked: RED & BLUE')
previous_button = None
current_button = None
# - draws -
screen.fill((0,0,0))
for rect, color in buttons.values():
pygame.draw.rect(screen, color, rect)
pygame.display.flip()
# - FPS -
clock.tick(5)
# - end -
pygame.quit()

Related

Deleting a Pixel From a Pygame Surface

I am trying to create a pixel-art making program using pygame (yes, I know there are better packages to use). The way that I am drawing pixels is via surface.set_at(). I need to know how to completely delete a pixel from a pygame surface, so that I can have an eraser tool. I do not want to fill the pixel in with the background color of the window, because that would still render when using pygame.image.save() to get an image file from the drawing. Can someone please help? Here is my code:
import pygame
import sys
import math
pygame.init()
clock = pygame.time.Clock()
pygame.display.set_caption("Pixel Studio v1.1")
screen = pygame.display.set_mode((960, 720), pygame.RESIZABLE)
scroll_speed = 5
canvas_size = (32, 16)
color = (255, 255, 255)
canvas_surf = pygame.Surface(canvas_size, pygame.SRCALPHA)
zoom = 12
mouse_down = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.image.save(canvas_surf, "canvas.png")
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == pygame.BUTTON_LEFT:
mouse_down = True
if event.button == pygame.BUTTON_WHEELUP:
if zoom > 2:
zoom -= scroll_speed
if event.button == pygame.BUTTON_WHEELDOWN:
zoom += scroll_speed
if event.type == pygame.MOUSEBUTTONUP:
if event.button == pygame.BUTTON_LEFT:
mouse_down = False
if zoom < 2:
zoom = 2
screen.fill((50, 50, 50))
#canvas_surf.fill((200, 200, 200))
canvas_surf_scaled = pygame.transform.scale(canvas_surf,(canvas_surf.get_width() * zoom, canvas_surf.get_height() * zoom))
canvas_rect = canvas_surf_scaled.get_rect(center=(screen.get_width()/2, screen.get_height()/2))
mouse_pos = pygame.mouse.get_pos()
if mouse_down:
canvas_surf.set_at((math.floor((mouse_pos[0] - canvas_rect.x) / zoom), math.floor((mouse_pos[1] - canvas_rect.y) / zoom)), color)
pygame.draw.rect(screen, ( 75, 75, 75), canvas_rect, 1,)
screen.blit(canvas_surf_scaled, canvas_rect)
pygame.display.flip()
clock.tick(60)
As discussed in the comments, you can make a pixel transparent by setting it to a value whose alpha value is zero.
#r #g #b #a
canvas_surf.set_at((x, y), (0, 0, 0, 0))

Python only running while loop once

import pygame
r_colour = (200, 100,100)
bg_colour = (0,175,200)
(width, height) = (600, 600)
screen = pygame.display.set_mode((width, height))
screen.fill(bg_colour)
pygame.draw.rect(screen, r_colour, (30, 30, 100, 100), 0)
pygame.display.flip()
running = True
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
screen.fill(bg_colour)
pygame.draw.rect(screen, r_colour, (20, 30, 100, 100), 0)
pygame.display.update()
if running == True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_s:
screen.fill(bg_colour)
pygame.draw.rect(screen, r_colour, (20, 30, 100, 100), 0)
pygame.display.update()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
break
running = False
pygame.quit()
I am trying to get the red square to move when pressing the 's' key, not sure as to why it only moves once and then stops. Very new to programming, so I am sorry, if it's long or hard to read.
A typical application has 1 single application loop. The application loop does:
handle the events and changes states dependent on the events
clears the display
draw the scene
update the display
The KEYDOWY event occurs once when a key is pressed, but it does not occur continuously when a key is hold down.
For a continuously movement you can get the state of the keys by pygame.key.get_pressed():
keys = pygame.key.get_pressed()
e.g. If the state of s is pressed can be evaluated by keys[pygame.K_s].
Add coordinates (x, y) for the position of the rectangle. Continuously manipulate the position in the main application loop, when a key is pressed.
e.g.
Increment x if d is pressed and decrement x if a is pressed.
Increment y if s is pressed and decrement y if w is pressed:
import pygame
r_colour = (200, 100,100)
bg_colour = (0,175,200)
(width, height) = (600, 600)
x, y = 20, 30
screen = pygame.display.set_mode((width, height))
running = True
while running:
# handle the events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# change coordinates
keys = pygame.key.get_pressed()
if keys[pygame.K_d]:
x += 1
if keys[pygame.K_a]:
x -= 1
if keys[pygame.K_s]:
y += 1
if keys[pygame.K_w]:
y -= 1
# clear the display
screen.fill(bg_colour)
# draw the scene
pygame.draw.rect(screen, r_colour, (x, y, 100, 100), 0)
# update the display
pygame.display.update()
pygame.quit()

Change colour on area of screen after mouseclick, and stay changed after release Pygame

so I have a background to my game. If an event (click) occurs, an area of the background changes colour. When I release the mouseclick, the screen updates and returns to the original colour which I don't want to happen.
The issue is clearly that the background updates after every iteration of the game loop, returning it to its original state, however, I believe I need the background to keep updating, but also for the clicks change to stay in permanent effect? So I need to find a way so that after a mouseclick, the
clicked area changes color, while the game continues to loop.
class Game(object):
def __init__(self):
self.squares = []
self.occupied = []
for x in range(0,8,1):
for y in range(0,8,1):
if (x + y) % 2 !=0:
pygame.draw.rect(screen, white, [x*100, y*100, 100, 100])
elif(x + y) % 2 ==0:
pygame.draw.rect(screen, aqua, [x*100, y*100, 100, 100])
self.squares.append([x,y])
if event.type == pygame.MOUSEBUTTONDOWN:
mx, my = pygame.mouse.get_pos()
mx = mx//100
my = my//100
pygame.draw.rect(screen, green, [mx*100, my*100, 100, 100])
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
game = Game()
pygame.display.update()
clock.tick(30)
pygame.quit()
quit()
Do not create a new instance of Game() each iteration. Create one instance only before the main loop, and add a method to Game class to update the color of the square.
Better to catch all the events in the main loop and not in the classes. When you catch an event, call the correlated class method to perform the intended action.
Below a working code:
import pygame
white = (255, 255, 255)
aqua = (0, 0, 100) #or whatever it really is, it's just a constant
green = (0, 255, 0)
class Game(object):
def __init__(self):
self.squares = []
self.occupied = []
for x in range(0,8,1):
for y in range(0,8,1):
if (x + y) % 2 !=0:
pygame.draw.rect(screen, white, [x*100, y*100, 100, 100])
elif(x + y) % 2 ==0:
pygame.draw.rect(screen, aqua, [x*100, y*100, 100, 100])
self.squares.append([x,y])
def colorsquare(self):
mx, my = pygame.mouse.get_pos()
mx = mx//100
my = my//100
pygame.draw.rect(screen, green, [mx*100, my*100, 100, 100])
game_over = False
pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
game = Game()
while not game_over:
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.MOUSEBUTTONDOWN:
game.colorsquare()
pygame.display.update()
clock.tick(30)

Fixing an error where the code goes unresponsive after one cycle

I'm trying to have the for loop run 5 iterations of the code below it but once it runs once and i try to click the rectangle the code goes unresponsive.
I can't see why this is happening so i'm looking for some help.
def Reaction_game():
intro = True
while intro == True:
for event in pygame.event.get():
#Stops game when close is selected
if event.type == pygame.QUIT:
file=open('currentuser.txt', 'w')
file.close()
pygame.quit()
quit()
Reaction_times=[]
for x in range (5):
clicked = False
BackGround = Background("background1.png",[0,0])
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
pygame.draw.rect(screen, black,(0,0,1000,55))
Font = pygame.font.SysFont('TitilliumWeb.ttf',72)
Label = Font.render("Get Ready:", 1, white)
screen.blit(Label, (380,0,325,75))
pygame.display.update()
time.sleep(2)
screen.blit(BackGround.image, BackGround.rect)
pygame.draw.rect(screen, black,(0,0,1000,55))
Font = pygame.font.SysFont('TitilliumWeb.ttf',72)
Label = Font.render("Go:", 1, white)
screen.blit(Label, (450,0,325,75))
pygame.display.update()
RectX = randrange(50,950)
RectY = randrange(60,513)
round_rect(screen,(RectX,RectY,75,40),(black),10,5,(white))
pygame.display.update()
TimeStart = time.time()
while clicked !=True:
mouse = pygame.mouse.get_pos()
if RectX+75 > mouse[0] > RectX and RectY+40 > mouse[1] > RectY:
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
else:
pass
Reaction_game()
I expect the code to run 5 iterations of this little reaction time game but it doesn't even get past the first loop before going unresponsive.
You have to use for event in pygame.event.get(): inside while clicked to get new events from system. Without this you have the same values in event.type and even.button.
Even pygame.mouse.get_pos() can't work correclty because it uses data created by pygame.event.get() (or similar)
If you have event MOUSEBUTTONDOWN, MOUSEBUTTONUP then you have mouse position in event.pos and you don't need pygame.mouse.get_pos()
while not clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if RectX+75 > event.pos[0] > RectX and RectY+40 > event.pos[1] > RectY:
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
EDIT:
You can keep Rectangle position and size in pygame.Rect()
RectX = randrange(50,950)
RectY = randrange(60,513)
rect = pygame.Rect(RectX, RectY, 75, 40)
and then you can use rect instead of (RectX,RectY,75,40)
round_rect(screen, rect, black , 10, 5, white)
and you can use rect to check if you clicked in rectangle rect.collidepoint(event.pos)
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if rect.collidepoint(event.pos):
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
EDIT: working example with other changes - ie. I use pygame.time.wait() instead of time.sleep() and pygame.time.get_ticks() instead of time.time(). Both use miliseconds instead of seconds.
import pygame
import random
# --- constants ---
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
# --- main ---
pygame.init()
screen = pygame.display.set_mode((1000, 600))
reaction_times= []
for x in range(5):
clicked = False
screen.fill(WHITE)
pygame.draw.rect(screen, BLACK, (0, 0, 1000, 55))
font = pygame.font.SysFont(None, 72)
label = font.render("Get Ready:", 1, WHITE)
screen.blit(label, (380, 0, 325, 75))
pygame.display.update()
pygame.time.wait(2000) # 2000ms = 2s
pygame.draw.rect(screen, BLACK, (0, 0, 1000, 55))
font = pygame.font.SysFont(None, 72)
label = font.render("Go:", 1, WHITE)
screen.blit(label, (450, 0, 325, 75))
pygame.display.update()
x = random.randrange(50, 950)
y = random.randrange(60, 513)
rect = pygame.Rect(x, y, 75, 40)
pygame.draw.rect(screen, BLACK, rect)
pygame.display.update()
time_start = pygame.time.get_ticks()
while not clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if rect.collidepoint(event.pos):
print('clicked')
time_end = pygame.time.get_ticks()
reaction_time = (time_end - time_start)/1000 # convert to seconds
reaction_times.append(reaction_time)
clicked = True
print(reaction_times)
pygame.quit()

Moving scalable rectangle with mouse in pygame

I'm trying to move a rectangle inside of pygame, and making it scalable.
The scalable rectangle code is something like this then I tried to add an event like this:
from pygame imports *
init()
rect1 = (rect1x, rect1y, 300,300)
rect1x = 0
rect1y = 0
while running:
x,y = mouse.get_pos()
if rect1Pressed == True:
rect1x = x
rect1y = y
for evnt in event.get():
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN:
if evnt.button == 1:
if rect1.collidepoint(mouse.get_pos()):
rect1Pressed == True
How would i incorporate the scalable rectangle and being able to make it move with the mouse? So that the window will follow the mouse motion. So it kinda is like a on your laptop where your able to scale the window and also move it around.
You could check which mouse button is pressed in the elif event.type == pg.MOUSEMOTION: block, e.g. if event.buttons[0]:, and then either move or scale the rect depending on the button. To move the rect, just add the event.rel to the rect.x and rect.y attributes.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect1 = pg.Rect(100, 100, 161, 100)
rect2 = pg.Rect(300, 200, 161, 100)
selected_rect = None
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
for rect in (rect1, rect2):
if rect.collidepoint(event.pos):
selected_rect = rect # Select the colliding rect.
elif event.type == pg.MOUSEBUTTONUP:
selected_rect = None # De-select the rect.
elif event.type == pg.MOUSEMOTION:
if selected_rect is not None: # If a rect is selected.
if event.buttons[0]: # Left mouse button is down.
# Move the rect.
selected_rect.x += event.rel[0]
selected_rect.y += event.rel[1]
else: # Right or middle mouse button.
# Scale the rect.
selected_rect.w += event.rel[0]
selected_rect.h += event.rel[1]
selected_rect.w = max(selected_rect.w, 10)
selected_rect.h = max(selected_rect.h, 10)
screen.fill((30, 30, 30))
pg.draw.rect(screen, (0, 100, 250), rect1)
pg.draw.rect(screen, (0, 200, 120), rect2)
pg.display.flip()
clock.tick(30)

Categories

Resources