How to add a click event for images in Pygame? - python

I have the following code. Which basically gets all the images from the folder apps and the subfolders of it. My problem is that I am trying to add a click event to all of the images to do the same thing. Basically "exec("apps/" + apps[app_count] + "/app.py")"
# -*- coding: utf-8 -*-
from pygame import *
import os
import pygame
import time
import random
import sys
_image_library = {}
class SeedOS():
def home(self):
(width, height) = (240, 320)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Seed OS')
pygame.font.init()
Font30 = pygame.font.SysFont('Arial', 30)
WHITE = (255,255,255)
BLACK = (0,0,0)
screen.fill(WHITE)
apps = os.walk("apps").next()[1]
app_count = 0
icon_width = 15
icon_height = 0
max_width = 155
pygame.display.flip()
while True:
while app_count < len(apps):
print apps[app_count]
image = pygame.image.load("apps/" + apps[app_count] + "/app.png").convert()
screen.blit(image, (icon_width, icon_height))
icon_width+=70
if icon_width > max_width:
icon_width = 15
icon_height +=70
app_count += 1
time2 = time.strftime('%H:%M:%S')
pygame.display.flip()
pygame.draw.rect(screen,BLACK,(0,290,240,30))
clock = Font30.render(time2, False, WHITE)
screen.blit(clock,(60,288))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.quit()
phone = SeedOS()
phone.home()
This is the part of the code that checks all of the things in the folder "apps"
while app_count < len(apps):
print apps[app_count]
image = pygame.image.load("apps/" + apps[app_count] + "/app.png").convert()
screen.blit(image, (icon_width, icon_height))
icon_width+=70
if icon_width > max_width:
icon_width = 15
icon_height +=70
app_count += 1
and appends all the images from each folder. I want on every icon click , execute it's "app.py" as in every app folders there are two files: "app.png" and "app.py".

You can add the coordinates of every image in the apps list and then use these coordinates with the pygame.mouse.get_pos() method :
while True:
while app_count < len(apps):
print apps[app_count]
apps[app_count] = (apps[app_count], icon_width, icon_height) # Adding coordinates to the list
image = pygame.image.load("apps/" + apps[app_count][0] + "/app.png").convert() # Adding an index to find the image in the tuple
screen.blit(image, (icon_width, icon_height))
icon_width+=70
if icon_width > max_width:
icon_width = 15
icon_height +=70
app_count += 1
time2 = time.strftime('%H:%M:%S')
pygame.display.flip()
pygame.draw.rect(screen,BLACK,(0,290,240,30))
clock = Font30.render(time2, False, WHITE)
screen.blit(clock,(60,288))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # MOUSEBUTTONLEFT
for a in apps:
if a[1] < pygame.mouse.get_pos()[0] < a[1]+IMAGEWIDTH and a[2] < pygame.mouse.get_pos()[1] < a[2] + IMAGEHEIGHT:
# Instruction to launch ("apps/" + a[0] + "/app.py")
All you have to do is to define is the width and the height from your icons (what you could do with pygame.Surface.get_size() if it's not the same for every app) and to replace the last line with the correct syntax. On windows you could use :
os.system("apps\\"+a[0]+"\\app.py") # of course you should import os first

Related

Why does pygame crash when I try to plot individual pixels to the screen for an image

I've been working on a piece of code that compares two images and tells me if they are similar, it also tells me which pixels are different in the image, after this it plots them into a pygame screen so that I can see which parts of the image are moving more clearly. The only problem is that it seems as if pygame cannot handle it or something and it crashes, no errors appear.
code:
import cv2
import pygame
from pygame.locals import *
lib = 'Map1.png'
lib2 = 'Map2.png'
lib3 = []
coordenatesx = []
coordenatesy = []
Read = list(cv2.imread(lib).astype("int"))
Read2 = list(cv2.imread(lib2).astype("int"))
counter = 0
for i in range(len(Read)):#y coords
for j in range(len(Read[i])):#x coords
blue = list(Read[i][j])[0]
green = list(Read[i][j])[1]
red = list(Read[i][j])[2]
blue2 = list(Read2[i][j])[0]
green2 = list(Read2[i][j])[1]
red2 = list(Read2[i][j])[2]
difference = (blue+green+red)-(blue2+green2+red2)
lib3.append(difference)
if difference <= 10 and difference >= -10:
counter+=1
coordenatesx.append(j)
coordenatesy.append(i)
if counter >= (i*j)*0.75:
print('They are similar images')
print('They are different by:', str((counter / (i * j)) * 100), '%')
else:
print('They are different')
print('They are different by:', str((counter / (i * j)) * 100), '%')
pygame.init()
screen = pygame.display.set_mode((500,500))
while 1:
screen.fill((20))
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
for l in range(len(coordenatesx)):
for v in range(len(coordenatesy)):
pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
pygame.display.update()
image1:
image2:
Pygame didn't crash. You know how defining a Pygame window without calling the pygame.event.get() method would cause problems, right? Well, when you put
for l in range(len(coordenatesx)):
for v in range(len(coordenatesy)):
pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
into the while loop that's supposed to constantly call the pygame.event.get() method, you are dramatically slowing down the looping process.
To see this with your eyes, add a print() statement into the loop, and see how slow it prints:
while 1:
screen.fill((20))
print("Looping...")
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
for l in range(len(coordenatesx)):
for v in range(len(coordenatesy)):
pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
pygame.display.update()
One fix is to move the pygame.event.get() call into the nested for loop (as well as the pygame.display.update() call if you want to see the updating):
while 1:
screen.fill((20))
for l in range(len(coordenatesx)):
for v in range(len(coordenatesy)):
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
pygame.draw.rect(screen, (blue, red, green), pygame.Rect(coordenatesx[l], coordenatesy[v], 1, 1))
pygame.display.update()
Use cv2/OpenCV and NumPy. Compute the absolute difference of the images with numpy.absolute. Sum the color channels and count the non-zero pixels with numpy.count_nonzero:
import cv2
import numpy
Read = cv2.imread('Map1.png').astype("int")
Read2 = cv2.imread('Map2.png').astype("int")
diff = numpy.absolute(Read - Read2).astype("uint8")
gray = numpy.sum(diff, axis=2)
count = numpy.count_nonzero(gray)
print(f"{count} / {gray.size}")
If you don't want to import NumPy:
diff = abs(Read - Read2)
gray = (diff[:,:,0] + diff[:,:,1] + diff[:,:,2])
diff = diff.astype("uint8")
count = sum([c > 0 for r in gray for c in r])
print(f"{count} / {gray.size}")
Minimal example:
import cv2
import numpy
import pygame
from pygame.locals import *
lib = 'Map1.png'
lib2 = 'Map2.png'
Read = cv2.imread(lib).astype("int")
Read2 = cv2.imread(lib2).astype("int")
diff = numpy.absolute(Read - Read2).astype("uint8")
gray = numpy.sum(diff, axis=2)
count = numpy.count_nonzero(gray)
print(f"{count} / {gray.size}")
pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
def cv2ImageToSurface(cv2Image):
if cv2Image.dtype.name == 'uint16':
cv2Image = (cv2Image / 256).astype('uint8')
size = cv2Image.shape[1::-1]
if len(cv2Image.shape) == 2:
cv2Image = np.repeat(cv2Image.reshape(size[1], size[0], 1), 3, axis = 2)
format = 'RGB'
else:
format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
return surface.convert_alpha() if format == 'RGBA' else surface.convert()
diff_surf = cv2ImageToSurface(diff)
run = True
while run:
clock.tick(100)
screen.fill((20))
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
run = False
screen.fill(0)
screen.blit(diff_surf, diff_surf.get_rect(center = screen.get_rect().center))
pygame.display.update()
pygame.quit()

How to speed up start time in pygame?

I am starting to write a game but whenever I run my code it takes 2 minutes to boot up and even then some methods are not working. The main ones that's not working are quitting pygame and drawGameScene().
My code is:
import os, random
from pygame import *
init()
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0, 20)
scalefactor = 2
FPS = 60
screenWidth = round(224 * scalefactor)
screenHeight = round(298 * scalefactor)
size = screenWidth, screenHeight
screen = display.set_mode(size)
button = 0
RED = (255, 0, 0)
BLUE = (0,0,255)
STATEGAME = 1
STATEQUIT = 3
curState = STATEGAME
titleFont = font.SysFont("Times New Roman",45)
def drawText(words, screen,position, color, font):
text = font.render(words, False, color)
textSize = text.get_size()
position[0] = position[0] - textSize[0]//2
position[1] = position[1] - textSize[1]//2
#centers the text
screen.blit(text,position)
def gameRun():
while curState != STATEQUIT:
if curState == STATEGAME:
drawGameScene()
eventCheck()
updater()
def eventCheck():
for evnt in event.get():
if evnt.type == QUIT:
curState == STATEQUIT
def updater():
pass
def drawGameScene():
draw.rect(screen,RED,(0,0,screenWidth,screenHeight))
drawText("High Score", screen, [0,0], BLUE, titleFont)
display.update
gameRun()
display.flip()
no error messages are given
Please Help, It's for a project
For the quitting pygame:
You should use the code as below:
for events in event.get():
if events.type == QUIT:
pygame.quit()
exit() #this is from sys module
This way, your pygame is quitted at the first place. So, you don't need anything about curstate, etc.
Also, you need to use while True statement to repeat the blitting process.
Full code:
import os, random
from pygame import *
from sys import exit
init()
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0, 20)
scalefactor = 2
FPS = 60
screenWidth = round(224 * scalefactor)
screenHeight = round(298 * scalefactor)
size = screenWidth, screenHeight
screen = display.set_mode(size)
button = 0
RED = (255, 0, 0)
BLUE = (0,0,255)
titleFont = font.SysFont("Times New Roman",45)
def drawText(words,screen,position,color,font):
text = font.render(words, False, color)
textSize = text.get_size()
position[0] = position[0] - textSize[0]//2
position[1] = position[1] - textSize[1]//2
#centers the text
screen.blit(text,position)
def gameRun():
drawGameScene()
eventCheck()
updater()
def eventCheck():
for events in event.get():
if events.type == QUIT:
quit()
exit()
def updater():
pass
def drawGameScene():
draw.rect(screen,RED,(0,0,screenWidth,screenHeight))
drawText("High Score", screen, [0,0], BLUE, titleFont)
#display.update()
while True:
gameRun()
display.flip()

How to attend image to pygame window based on paths from array?

I'm trying to build a mobile interface in pygame. I have a folder called apps and every app contains two files: "app.py" and "app.png". Currently I can get the app name the folder contents. the file contents are saved in an array. I am trying to get the "app.png" from every folder and add it to the pygame screen?
Here is my current code:
from pygame import *
import os
import pygame
import time
import random
_image_library = {}
class SeedOS():
def home(self):
def get_image(path):
global _image_library
image = _image_library.get(path)
if image == None:
canonicalized_path = path.replace('/', os.sep).replace('\\', os.sep)
image = pygame.image.load(canonicalized_path)
_image_library[path] = image
return image
(width, height) = (240, 320)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Seed OS')
BLACK = (0,0,0)
screen.fill(BLACK)
apps = os.walk("apps").next()[1]
app_count = 0
while app_count < len(apps):
print apps[app_count]
icon_width = 0
icon_height = 0
screen.blit(get_image("apps/" + apps[app_count] + "/app.png"), (icon_width, 0))
icon_width+=70
app_count += 1
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
phone = SeedOS()
phone.home()
Notice that icon_width is getting re-initialized to zero with each iteration through the while-loop:
while app_count < len(apps):
print apps[app_count]
icon_width = 0
icon_height = 0
screen.blit(get_image("apps/" + apps[app_count] + "/app.png"), (icon_width, 0))
icon_width+=70
app_count += 1
So the screen.blit will always place the image at (0, 0); icon_width+=70 is nugatory. Instead you could use something like:
icon_width = 0
icon_height = 0
max_width = 240 # <-- you'll need to decide how to set this, depending on size of screen
while app_count < len(apps):
print apps[app_count]
screen.blit(get_image("apps/" + apps[app_count] + "/app.png"),
(icon_width, icon_height))
icon_width += 70
if icon_width > max_width:
icon_width = 0
icon_height += 70 # <-- assuming app.pngs have constant height
app_count += 1
This is still pretty rudimentary -- it does not address the possibility of
different sized app.pngs nor what to do if there are more images than can fit
on the screen. But this should get you over the first hump -- how to place the images at different locations.

I get an incorrect position from .get_rect()?

I'm currently working on a school project where I'm making a "hexcells" similar game in pygame and now I'm trying to blit an a new image if the user has clicked a current image. It will blit an image in the top left area, if clicked in the top left area, but not if I click any of the existing images. I told the program to print the coordinates from the images with help of the .get_rect() function, but it remains the same whereever I click and the coordinates aren't even where a image is. Can someone help me understand how this works and help me blit the new images on top of the existing images? Code below is not the entire document, however there is so much garbage/trash/unused code so I'd thought I spare you the time of looking at irrelevant code. Also sorry if the formatting is wrong or the information isn't enough, I tried my best.
import pygame, sys
from pygame.locals import *
#Magic numbers
fps = 30
winW = 640
winH = 480
boxSize = 40
gapSize = 75
boardW = 3
boardH = 3
xMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
yMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
#Lil bit o' color R G B
NAVYBLUE = ( 60, 60, 100)
correctCords = [[175,275,375],[375,275,175]]
bgColor = NAVYBLUE
unC = pygame.image.load("unC.png")
cor = pygame.image.load("correct.png")
inc = pygame.image.load("wrong.png")
correct = "Correct"
inCorrect = "Incorrect"
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((winW, winH))
mousex = 0 #stores x-coordinate of mouse event
mousey = 0 #stores y-coordinate of mouse event
pygame.display.set_caption("Branches")
DISPLAYSURF.fill(bgColor)
gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize)
while True:
mouseClicked = False
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex,mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
pos = pygame.mouse.get_pos()
mouseClicked = True
unCa = unC.get_rect()
corA = cor.get_rect()
print unCa
print corA
print pos
if unCa.collidepoint(pos):
DISPLAYSURF.blit(cor,(mousey,mousex))
"""lada = unC.get_rect()
lada =
if mousex and mousey == lada:
for x in correctCords:
for y in x:
for z in x:
if mousey and mousex == z and y:
DISPLAYSURF.blit(cor,(mousey,mousex))
print lada"""
pygame.display.update()
FPSCLOCK.tick(fps)
def gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize):
grid = []
cordX = []
cordY = []
correctRecs = []
#cordinates = []
#cordinates.append([])
#cordinates.append([])
#cordinates.append([])
#this is basically getBoard() all over again
#This part will arrange the actual backend grid
for row in range(3):
grid.append([])
#cordinates[0].append(gapSize+(row+1)*100)
#cordinates[1].append(gapSize+(row+1)*100)
#cordinates[2].append(gapSize+(row+1)*100)
for column in range(3):
grid[row].append(inCorrect)
for row in range(3):
cordX.append([])
for column in range(3):
cordX[row].append(gapSize+(row+1)*100)
for row in range(3):
cordY.append([])
for column in range(3):
cordY[row].append(gapSize+(column+1)*100)
#print cordX[0][0], cordY[0][0]
grid[0][2] = correct
grid[1][1] = correct
grid[2][0] = correct
#Y-AXEL SKRIVS FoRST ([Y][X])
#print cordinates[2][1]
DISPLAYSURF.blit(cor,(100,100))
#Let's draw it as well
for row in range(3):
for column in range(3):
DISPLAYSURF.blit(unC,(gapSize+(row+1)*100,gapSize+(column+1)*100))
main()
Also real sorry about the horrible variable naming and occasional swedish comments.
unCa = unC.get_rect() gives you only image size - so use it only once at start (before while True) - and later use the same unCa all the time to keep image position and change it.
btw: better use more readable names - like unC_rect
ie.
# move 10 pixel to the right
unC_rect.x += 10
# set new position
unC_rect.x = 10
unC_rect.right = 100
unC_rect.topleft = (10, 200)
unC_rect.center = (10, 200)
# center on screen
unC_rect.center = DISPLAYSURF.get_rect().center
etc.
And then use this rect to blit image
blit(unC, unC_rect)
and check collision with other rect
if unC_rect.colliderect(other_rect):
or with point - like mouse position
elif event.type == MOUSEMOTION:
if unC_rect.collidepoint(pygame.mouse.get_pos()):
hover = True
# shorter
elif event.type == MOUSEMOTION:
hover = unC_rect.collidepoint(pygame.mouse.get_pos()):

Why doesnt my sprite move?

I'm new to Pygame and I'm trying to move my sprite on my background image.
My sprite is not re appearing after it moves? Any ideas?
This is most of the program without some screens.
I have been trying to get this to work for many hours,
#dependencies
import pygame as P
import random as R
def welcome(screen):
#load background
bg = P.image.load("space-wallpaper.jpg")
screen.blit(bg,[0,0])
#set fonts etc
font = P.font.Font("Space_Age.ttf",60)
width, height = screen.get_size()
#play button
message = "PLAY "
text = font.render(message,1,[255 , 0, 0])
rect = text.get_rect()
x, y = text.get_size()
rect = rect.move((width - x)/2, (height - y)/2)
screen.blit(text,rect)
#high_score button
message = "HIGH SCORE "
text = font.render(message,1,[255 , 0, 0])
rect = text.get_rect()
x, y = text.get_size()
rect = rect.move((width - x)/2, (height - y)/2 +100)
screen.blit(text,rect)
def play_button(screen):
"""launch welcome screen.
"""
#welcome screen play button
font = P.font.Font("Space_Age.ttf",60)
message = "PLAY "
play_x,play_y = font.size(message)
play_text = font.render(message,1,[255 , 0, 0])
width, height = 800,600
screen.blit(play_text,[(width - play_x)/2, (height - play_y)/2])
play_rect = play_text.get_rect().move((width - play_x)/2, (height - play_y)/2)
P.display.flip()
return(play_rect)
def welcome_background(screen):
# Welcome screen background
bg = P.image.load("space-wallpaper.jpg")
screen.blit(bg,[0,0])
P.display.update()
def high_score_screen(screen):
"""opens the highscore screen"""
high_score_bg = P.image.load("bg_game.jpg")
screen.blit(high_score_bg,[0,0])
P.display.update()
def splash_screen(screen):
"""loads the first screen in the game with a 3 sec wait"""
splash_image = P.image.load('splash.jpg')
screen.blit(splash_image,[0,0])
P.display.update()
P.time.wait(2001)
def play_game(screen):
"""loads the play game screen"""
game_bg = P.image.load("bg_game.jpg")
screen.blit(game_bg,[0,0])
P.display.update()
def move_right(screen,x_cord,flagship):
dist = 20
play_game(screen)
x_cord = x_cord + dist
print(x_cord)
screen.blit(flagship,[x_cord])
P.display.update()
def key_detection(screen,flagship,x_cord):
key = P.key.get_pressed()
if key[P.K_RIGHT]:
move_right(screen,x_cord,flagship)
#move_right()
elif key[P.K_LEFT]:
print("left")
class Sprite():
def __init__(self,screen):
""" The constructor of the class """
self.flagship = P.image.load("sprite2.png")
self.x = 0
self.y = 0
def display(self,screen):
#screen.blit(self.sprite,[self.x,self.y]) changed by geoff
screen.blit(self.flagship,[self.x,self.y])
P.display.update()
_init_
# dependencies
from mods import *
import pygame as P
#initialise pygame
P.init()
def main():
# parameters to control pygame basics
screen_size = width, height = 800,600 #sixe of playing screen
P.display.set_caption('Space Smasher!')
screen = P.display.set_mode(screen_size)
clock = P.time.Clock() # timer used to control rate of looping
loop_rate = 20 #number of times per second does loop
play = True #control the playing of the actual game
splash_screen(screen)
welcome(screen)
P.display.flip()
rect_play = play_button(screen)
flagship = Sprite(screen)
while play:
key_detection(screen,flagship.image,flagship.x)
# for event in P.event.poll(): changed by geoff
event = P.event.poll() #did the player do something?
if event.type == P.QUIT:
play = False
if event.type == P.MOUSEBUTTONDOWN:
player_position = P.mouse.get_pos()
if rect_play.collidepoint(player_position):
play_game(screen)
flagship.display(screen)
P.quit()
if __name__ == '__main__':
main()
You are not calling either of your functions or your classes anywhere. You need a while loop that is similarly structured to this:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
#Do your movements
With the following imports at the top:
import pygame, sys
from pygame.locals import *
Here is an example of moving an object with the keys:
import pygame, sys
from pygame.locals import *
pygame.init()
WIDTH=1439
HEIGHT=791
DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Hello Pygame World!')
pygame.key.set_repeat(1, 10)
circx, circy = 200, 150
CIRWIDTH=20
while True: # main game loop
if pygame.key.get_pressed()[pygame.K_UP]:
circy-=5
if pygame.key.get_pressed()[pygame.K_DOWN]:
circy+=5
if pygame.key.get_pressed()[pygame.K_RIGHT]:
circx+=5
if pygame.key.get_pressed()[pygame.K_LEFT]:
circx-=5
try:
for event in pygame.event.get():
if event.type == QUIT or event.key == pygame.K_ESCAPE or event.key == pygame.K_q:
pygame.quit()
sys.exit()
except AttributeError:
pass
DISPLAYSURF.fill((0, 0, 0))
pygame.draw.circle(DISPLAYSURF, (158, 219, 222), (circx, circy), CIRWIDTH)
pygame.display.flip()
Main loop should be similar to:
while True:
# events - check keyboad and mouse and change player direction or speed
# move - move sprite with speed and direction
# check collison
# draw background, all objects and all sprites
# clock - to keep constant speed - FPS (Frames Per Seconds)
So you have to move sprites in every loop and draw them.

Categories

Resources