Using MOUSEBUTTONDOWN in pygame - python

So I am trying to do some very basic things in pygame. It is my first few days using it so I am a beginner. I am trying to change the color of something whenever I press it with the mouse. I know how to change the colors by timing which is what I have my code down below. I am trying to change the color of the cloud in my code below, if you run it you will see the cloud is the top left and I have it changing between white and black every three seconds but I want it to change based on mousebuttondown. Thanks
import pygame, time, sys
from pygame.locals import *
def drawItem(windowSurface, x, y):
pygame.draw.polygon(windowSurface, RED, ((0+x, 100+y),(100+x, 100+y), (50+x, 50+y)))
pygame.draw.polygon(windowSurface, GREEN, ((0+x,100+y),(100+x,100+y),(100+x,200+y),(0+x,200+y)))
pygame.init()
windowSurface = pygame.display.set_mode((500, 400), 0, 32)
pygame.display.set_caption("Lab 9")
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
GRASS = (26, 82, 26)
SKY = (179,237,255)
color = SKY
flag = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
windowSurface.fill(SKY)
drawItem(windowSurface,200,120)
pygame.draw.rect(windowSurface, GRASS, (0,300,500,500),0)
house = ((0+50, 100+50),(100+50, 100+50), (50+50, 50+50), (50+100, 50+100))
for i in range(3):
pygame.draw.circle(windowSurface,color, house[i], 80)
if flag == False:
color = WHITE
flag = True
elif flag == True:
color = BLACK
flag = False
pygame.display.update()
time.sleep(3)

You've already discovered how to test for the type of an event (checking whether event.type == QUIT).
You can extend this to check whether it's a mouse button click. Stick this in your for event in pygame.event.get() loop:
if event.type == MOUSEBUTTONDOWN:
flag = not flag # This will swap the value of the flag
Then get rid of the flag = True and flag = False lines below, since you don't need them anymore. Also get rid of the time.sleep() call; or at least change it to a reasonable frame rate (like time.sleep(0.2) = 50 frames per second).

Related

How can I improve my color change programm?

A few days ago I found a couple of dead pixels on my laptop screen. Googled how to remove them without going to the service center, but nothing helped. I decided to create a simple code myself to go through all possible colors in order to finally make a verdict on whether I should go to a service center or not.
I decided to write code in Python, because on I can quickly create an algorithm that would solve my problem, but I met with a problem in speed.
Walking through one color (blue in my case) takes about 1.64 seconds, then it takes about 29 hours to walk through all the colors, which is quite a long time. Is there any way to speed up the process? Or should I choose some other method?
import pygame
WIDTH = 200
HEIGHT = 200
FPS = 144
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
running = True
r = 0
g = 0
b = 0
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
b += 1
if b % 256 == 0:
b = 0
g += 1
if g % 256 == 0:
g = 0
r += 1
if r % 256 == 0:
break
screen.fill((r, g, b))
pygame.display.flip()
Here's your script modified to randomly cycle through RGB on/off permutations:
import pygame
import random
WIDTH = 200
HEIGHT = 200
FPS = 144
# permutations of on/off for R, G & B
colours = ((0, 0, 0),
(255, 0, 0),
(0, 255, 0),
(0, 0, 255),
(255, 255, 0),
(0, 255, 255),
(255, 0, 255),
(255, 255, 255))
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# testing out the walrus operator
while (colour := random.choice(colours)) == screen.get_at((0, 0))[:3]:
# print(f"dupe: {colour} {screen.get_at((0,0))}")
pass
# colour = random.choice(colours)) # no dupe check
screen.fill(colour)
# print(colour)
pygame.display.flip()
clock.tick(FPS)
The duplicate colour prevention is a little ugly but I was testing out an assignment expression.
Enable the print statements to confirm that you're not getting duplicate colours although it probably doesn't matter. You can get rid of the duplicate check and uncomment the original colour assignment if you don't like the :=.

Transparency problem displaying text with Pygame

enter image description hereI would like to display transparent text on a surface that is sized based on the length of the text.
The problem is that the text has a black background even though "None" is specified as the background in the "render" command.
I tried to apply the solutions given for questions similar to mine but they didn't work.
I attach the code and thank you for any suggestions.
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800, 600))
screen.fill ((0,0,255))
# red square
surf1 = pygame.Surface((200, 200))
surf1.fill((255, 0, 0))
rect1 = surf1.get_rect()
rect1.topleft = (50, 50)
screen.blit(surf1, rect1)
# Play button
fnt = pygame.font.SysFont("Times New Roman", 27, bold=True)
btn_play = fnt.render("Play", True, (51, 26, 0), None)
btn_play_size = btn_play.get_size()
btn_play_surface = pygame.Surface(btn_play_size)
btn_play_surface.blit(btn_play, (0, 0))
rect_btn_play = pygame.Rect(380, 50, btn_play_size[0], btn_play_size[1])
screen.blit(btn_play_surface, (380, 50))
pygame.display.flip()
def events():
done = False
while not done:
for ev in pygame.event.get():
if ev.type == QUIT:
return "quit"
elif ev.type == MOUSEBUTTONDOWN:
click = ev.pos
if rect1.collidepoint(click):
return "Red squre"
elif rect_btn_play.collidepoint(click):
return "Play"
else:
print ("You clicked outside of the surfaces")
while True:
event = events()
print (event)
if event == "quit":
break
pygame.quit()
The problem is the surface you are placing the text on. If you want to keep the transparency in the formation of the text, you need to create a pygame.Surface object with an per pixel alpha format. Use the pygame.SRCALPHA flag:
btn_play_surface = pygame.Surface(btn_play_size)
btn_play_surface = pygame.Surface(btn_play_size, pygame.SRCALPHA)
Alternatively you can set the color key for the transparent color with set_colorkey:
btn_play_surface = pygame.Surface(btn_play_size)
btn_play_surface.set_colorkey((0, 0, 0))

Is there a way to get pygame to detect what color my cursor is on

I'm trying to make a game where it spawns another circle every time you click on a circle. And the error i'm getting is "TypeError: 'bool' object is not callable". I'm looking for a solution that doesn't completly change the code since i'm new and want to understand the code myself. But at this point i'll take any help.
import pygame
import random
import time
from pygame.math import Vector2
# Define some colors
BLACK = (0, 0, 0)
WHITE = (247, 247, 247)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (225,225,0)
tuple1 = (247, 247, 247, 255)
# Setup
pygame.init()
# Set the width and height of the screen [width,height]
surface = pygame.display.set_mode( (2560, 1440) )
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# Hide the mouse cursor
pygame.mouse.set_visible(0)
# Speed in pixels per frame
x_speed = 0
y_speed = 0
# Current position
cursor = pygame.image.load('cursor.png').convert_alpha()
pygame.image.load("pattern.jpg")
background_image = pygame.image.load("pattern.jpg").convert()
circposy = 770
circposx = 1280
# -------- Main Program Loop -----------
while done ==False:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
done = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Drawing Code
surface.fill(WHITE)
# First, clear the screen to WHITE. Don't put other drawing commands
# above this, or they will be erased with this command.\
player_position = pygame.mouse.get_pos()
a = 0
b = 1
p=player_position[a]
o=player_position[b]
player_position = (p,o)
pygame.draw.circle(surface,RED,[circposx,circposy], 40)
tuple2 = surface.get_at(pygame.mouse.get_pos())
print (tuple2)
q = p - 2545
w = o - 2545
surface.blit( cursor, (q, w) )
a=0
result = tuple(map(int, tuple2)) > tuple1
print (result)
while event.type == pygame.MOUSEBUTTONDOWN:
done = True
if result == True():
a+1
surface.fill(WHITE)
pygame.draw.circle(surface,RED,[circposx + randint, circposy+randint],40)
print (a)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit frames per second
clock.tick(144)
# Close the window and quit.
pygame.quit()
cursor.png
The short answer is that the code is trying to call True(), which isn't a function.
while event.type == pygame.MOUSEBUTTONDOWN:
done = True
if result == True(): # <<-- HERE
a+1
surface.fill(WHITE)
pygame.draw.circle(surface,RED,[circposx + randint, circposy+randint],40)
Simply change this to True.
But you will also need to define what randint is a few lines lower. Did you mean random.randint( 0, 500 ) or suchlike? And fixing this leads to another error, because the surrounding loop to this code, is an infinite loop:
while event.type == pygame.MOUSEBUTTONDOWN: # <<-- HERE
done = True
if result == True:
a+1
surface.fill(WHITE)
rand_x = random.randint( 0, 500 )
rand_y = random.randint( 0, 500 )
pygame.draw.circle(surface,RED,[circposx + rand_x, circposy+rand_y],40)
Because there is no way event.type can ever change inside that loop. This should probably read:
if event.type == pygame.MOUSEBUTTONDOWN:
If I may make some suggestions:
Put all your event handling to a single place.
There's some doubling-up of event handling, and it would have prevented that infinite loop.
Move your screen dimensions into variables
SCREEN_WIDTH = 2560
SCREEN_HEIGHT = 1440
Instead of having constant numbers through the code (e.g.: 2545) make these functions of the screen size.
SCREEN_MARGIN = SCREEN_WIDTH - round( SCREEN_WIDTH * 0.10 )
q = p - SCREEN_MARGIN
If you want to detect what color your cursor is on, you can use pyautogui. Make sure you have pyautogui installed. type pip install pyautogui. If it doesn't install successfully, you already have it installed.
# Import everything
import pygame
import pyautogui
from pyautogui import *
# Initialize
pygame.init()
# Get mouse position
mouse_pos = pygame.mouse.get_pos()
x = mouse_pos[0]
y = mouse_pos[1]
# Get Color
r = pyautogui.pixel(x,y)[0]
g = pyautogui.pixel(x,y)[1]
b = pyautogui.pixel(x,y)[2]
color = [r,g,b]
Hopefully, you found this helpful!

Pygame click on image (not a rectangle)

This is the part of my code, where the problem is:
button = pygame.image.load("button1.png")
screen.blit(button, (100, 100))
This image looks like this:
[
I need to increase a value of a variable, when the user clicks on the image.
I tryed some solutions, but most of them was drawing an "invisible" rectangle over the picture, and the variable's value vas increasing, even if someone clicked on the white space near the triangle.
It's quite easy with the mask module.
From the docs:
Useful for fast pixel perfect collision detection. A mask uses 1 bit per-pixel to store which parts collide.
First, create a Mask from the image
mask = pygame.mask.from_surface(button)
Then, when checking for the mouse click event, check if the point in the mask is set.
Here's a simple example:
import pygame
def main():
pygame.init()
screen = pygame.display.set_mode((480, 320))
button = pygame.image.load('button.png').convert_alpha()
button_pos = (100, 100)
mask = pygame.mask.from_surface(button)
x = 0
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
return
if e.type == pygame.MOUSEBUTTONDOWN:
try:
if mask.get_at((e.pos[0]-button_pos[0], e.pos[1]-button_pos[1])):
x += 1
print(x)
except IndexError:
pass
screen.fill((80,80,80))
screen.blit(button, button_pos)
pygame.display.flip()
main()
Example button.png for testing:
There's no easy way to do this in pygame other than manually calculating where the mouse is and figuring out if it's in the triangle or not.
The image you're loading (button1.png) is a square image, and so there's no way for pygame or any other library to know what it's "actual" shape is. You'll either have to do it yourself or be okay with the user being able to click on the white space.
You could use Surface.get_at() to check the color of the pixel where the mouse clicks. If it's the background color (white in your case) you consider it outside, otherwise is inside and you trigger the action.
Here a working example. The insideimage function checks that the click is inside the surface button (the rectangle) and checks the color of the pixel at mouse coordinates. Returns True if the click is inside the surface and the color is not white.
This works if the background color is not used again inside the image.
import sys
import pygame
SCREENWIDTH = 500
SCREENHEIGHT = 500
pygame.init()
screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
button = pygame.image.load("button1.png")
screen.blit(button, (100, 100))
def insideimage(pos, rsurf, refcolor):
"""rsurf: Surface which contains the image
refcolor: background color, if clicked on this color returns False
"""
refrect = rsurf.get_rect().move((100, 100))
pickedcol = screen.get_at(pos)
return refrect.collidepoint(pos) and pickedcol != refcolor
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
valid = insideimage(event.pos, button, (255, 255, 255, 255))
#(255, 255, 255, 255) this is color white with alpha channel opaque
print(valid)
pygame.display.update()

pygame.time.wait() crashes the program

In a pygame code I wannted to do a title that changes colors.
I tried to do a simple title that changes colors, but it not even turned the color to blue (or do it for a second), and the program crash. The code:
title_font = pygame.font.SysFont("monospace", TITLE_SIZE)
while True:
title = title_font.render("game", 5, RED)
game_display.blit(title, TITLE_POS)
pygame.display.update()
pygame.time.wait(2000)
title = title_font.render("game", 5, BLUE)
game_display.blit(title, TITLE_POS)
pygame.display.update()
pygame.time.wait(3000)
title = title_font.render("game", 5, RED)
game_display.blit(title, TITLE_POS)
pygame.display.update()
pygame.time.wait(2000)
It also happens with pygame.time.delay(), and I don't know where is the problem...
Don't use pygame.time.wait or delay because these functions make your program sleep for the given time and the window becomes unresponsive. You also need to handle the events (with one of the pygame.event functions) each frame to avoid this.
Here are some timer examples which don't block: Countdown timer in Pygame
To switch the colors, you can just assign the next color to a variable and use it to render the text.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
title_font = pygame.font.SysFont('monospace', 50)
BACKGROUND_COLOR = pygame.Color('gray12')
BLUE = pygame.Color('blue')
RED = pygame.Color('red')
# Assign the current color to the color variable.
color = RED
timer = 2
dt = 0
done = False
while not done:
# Handle the events.
for event in pygame.event.get():
# This allows the user to quit by pressing the X button.
if event.type == pygame.QUIT:
done = True
timer -= dt # Decrement the timer by the delta time.
if timer <= 0: # When the time is up ...
# Swap the colors.
if color == RED:
color = BLUE
timer = 3
else:
color = RED
timer = 2
screen.fill(BACKGROUND_COLOR)
title = title_font.render('game', 5, color)
screen.blit(title, (200, 50))
pygame.display.flip()
# dt is the passed time since the last clock.tick call.
dt = clock.tick(60) / 1000 # / 1000 to convert milliseconds to seconds.
pygame.quit()

Categories