My code should be right, however it works only if I move my mouse, even if I didn't even set up one.
the code should draw concentric circles moving.
I have even tried by blocking the mouse, but it still doesn't work
import pygame
import math
import time
pygame.init()
screen = pygame.display.set_mode([800,600])
black = (0,0,0)
keep_going = True
white = (255,255,255)
freq = 10
num_circles = 0
radius = 0
while keep_going:
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
radius = radius + 1
num_circles = math.ceil(radius / freq)
screen.fill(white)
radiusMax = num_circles * freq
pace = freq / radiusMax
for y in range(num_circles, 1, -1):
radiusY = int(((pace * (num_circles - y)) + pace) * radiusMax) + (radius % freq)
pygame.draw.circle(screen, black,(400, 300), radiusY, 1)
pygame.display.update()
pygame.quit()
I would like to know why the hell I get this kind of bug, how to solve it, and if it's not possible, a possible solution.
The issue is caused, because you do all the code in the event loop. The code in the event loop is executed only, when an event occurs, such as mouse movement (pygame.MOUSEMOTION).
Do the drawing in the main loop rather than the event loop, to solve the issue:
while keep_going:
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
#<--
#<--
#while input() != "quit":
#for x in range(1): #importante
raggio = raggio + 1
num_cerchi = math.ceil(raggio / freq)
screen.fill(white)
raggioMax = num_cerchi * freq
passo = freq / raggioMax
#time.sleep(5)
for y in range(num_cerchi, 1, -1):
# 1, -1
raggioY = int(((passo * (num_cerchi - y)) + passo) * raggioMax) + (raggio % freq)
pygame.draw.circle(screen, black,(400, 300), raggioY, 1)
#raggio = raggio+1 #importante
clock.tick(60)
pygame.display.update()
pygame.quit()
Related
Im creating a program that will show every image from a folder, i created a function for scrolling because in case there were a lot of images it wouldn't fit the screen, the problem is that after reaching 65536 on the y value, it will start bliting at 0 again, like placing the new names on top of the old ones.
This is a preview code that recreates my problem, what should happen when you press a key is a black screen or maybe a little of green on top, what really happens is that the top half is the y = 0 and the bottom half is y = -65540
import pygame
screen = pygame.display.set_mode((500,500))
colors = pygame.Surface((50,66000))#73825
colors.fill("green", (0,33, 50, 65600))
x = 0
running = True
while running:
pygame.time.Clock().tick(30)
screen.fill("black")
screen.blit(colors, (225,x))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYUP:
x = 0
if event.type == pygame.KEYDOWN:
x = -65540
if event.type == pygame.QUIT:
running = False
this only happens when using blit as rects work perfectly beyond the 65k pixel
it wouldn't fit the screen, the problem is that after reaching 65536
65535 is 0xffff, which is the maximum number that can be represented by 2 bytes or a variable of type "uint16". Likely this is the internal data type pygame uses to represent a pixel on the screen or the size of a pygame.Surface. This is far enough for any display in the world.
It is not a good idea to create a pygame.Surface of this size. It would be better to draw the parts of the images on the screen that should be displayed in each frame.
Minimal example of a scrollable image grid of images of the same size:
import pygame, random, math
screen = pygame.display.set_mode((500, 500))
scr_w, scr_h = screen.get_size()
img_w, img_h = 300, 200
images = []
for i in range(98):
img = pygame.Surface((img_w, img_h))
img.fill([random.randrange(256) for _ in range(3)])
images.append(img)
columns = 10
rows = math.ceil(len(images) / columns)
offset_x = 0
offset_y = 0
def fill_display():
row = offset_y // img_h
display_y = (img_h - (offset_y % img_h)) - img_h
while display_y < scr_w:
col = offset_x // img_w
display_x = (img_w - (offset_x % img_w)) - img_w
while display_x < scr_h:
i = row * columns + col
if i < len(images):
screen.blit(images[i], (display_x, display_y))
display_x += img_w
col += 1
display_y += img_h
row += 1
clock = pygame.time.Clock()
running = True
while running:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
offset_x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 20
offset_y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 20
offset_x = min((columns) * img_w - scr_w, max(0, offset_x))
offset_y = min((rows) * img_h - scr_h, max(0, offset_y))
screen.fill("black")
fill_display()
pygame.display.update()
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()
The code should display 1 or 2 circles depending on what you ask, and the program asks the user for the frequency of both circles.
I'm pretty sure the code works right, but the problem is that when the circles are displayed, 1 of the circles keeps flashing, but I don't know how to adjust it.
I have tried by playing around with it, by moving the update after or before, by updating it 2 times, after or before, anyway i'm stuck and I don't know how I should do it
import pygame
import math
import time
clock = pygame.time.Clock()
pygame.init()
pygame.display.set_caption("circles")
screen = pygame.display.set_mode([1000,700])
width_2 = int(screen.get_width() / 2)
width_3 = int(screen.get_width() / 3)
height_center = int(screen.get_height() / 2 )
black = (0,0,0)
keep_going = True
onecircle = False
twocircles = False
white = (255,255,255)
blue = (0,0,255)
red = (255,0,0)
freq = 0
circle1spot = (0,0)
circle2spot = (0,0)
freq2 = 0
pointradius = 3
num_circles = 0
num_circles2 = 0
radius = 0
radius2 = 0
centerradius = 20
howmanycircles = int(input("How many circles? \n"))
if howmanycircles == 1:
onecircle = True
elif howmanycircles == 2:
twocircles = True
else:
print("Answer not correct, 1 circle selected by default")
onecircle = True
if howmanycircles == 1:
freqinput = int(input("Frequency 1 circle, MIN [1], MAX [148]: \n"))
freq = 150 - freqinput
elif howmanycircles == 2:
freqinput = int(input("Frequency 1 circle, MIN [1], MAX [148]: \n"))
freq = 150 - freqinput
freqinput2 = int(input("Frequency 2 circle, MIN [1], MAX [148]: \n"))
freq2 = 150 - freqinput2
def circle1(radius, centerradius):
radius = radius + 1
num_circles = math.ceil(radius / freq)
#screen.fill(white)
radiusMax = num_circles * freq
pace = freq / radiusMax
for y in range(num_circles, 1, -1):
radiusY = int(((pace * (num_circles - y)) + pace) * radiusMax) + (radius % freq)
pygame.draw.circle(screen, black, circle1spot, centerradius, 1 )
pygame.draw.circle(screen, black, circle1spot, radiusY, 1)
#pygame.display.update()
return radius
def circle2(raggio2, centerradius):
radius2 = radius2 + 1
num_circles2 = math.ceil(radius2 / freq2)
#screen.fill(white)
radiusMax = num_circles2 * freq2
pace = freq2 / radiusMax
for y in range(num_circles2, 1, -1):
radiusY = int(((pace * (num_circles2 - y)) + pace) * radiusMax) + (radius2 % freq2)
pygame.draw.circle(screen, red, circle2spot, centerradius, 1 )
pygame.draw.circle(screen, red, circle2spot, radiusY, 1)
#pygame.display.update()
return radius2
while keep_going:
for event in pygame.event.get():
if event.type == pygame.QUIT:
keep_going = False
if event.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pressed()[0]:
#mousedownleft = True
circle1spot = pygame.mouse.get_pos()
print(circle1spot)
if pygame.mouse.get_pressed()[2]:
#mousedownright = True
circle2spot = pygame.mouse.get_pos()
pygame.draw.circle(screen, blue, (width_3,height_center), pointradius, 3 )
pygame.draw.circle(screen, blue, ((width_3*2),height_center), pointradius, 3 )
pygame.draw.circle(screen, blue, ((width_2),height_center), pointradius, 3 )
if onecircle == True:
radius = circle1(radius,centerradius)
pygame.display.update()
elif twocircles == True:
radius = circle1(radius,centerradius) #this is the critical zone
pygame.display.update() #this is the critical zone
radius2 = circle2(radius2, centerradius) #this is the critical zone
pygame.display.update() #this is the critical zone
screen.fill(white) #this is the critical zone
pygame.quit()
I'm looking for a possible solution to make it work correctly and to get it refreshed correctly
It is sufficient to do one single pygame.display.update() at the end of the main loop.
clear the display
do all the drawing
update the display
while keep_going:
# [...]
# 1. clear the display
screen.fill(white)
# 2. do all the drawing
pygame.draw.circle(screen, blue, (width_3,height_center), pointradius, 3 )
pygame.draw.circle(screen, blue, ((width_3*2),height_center), pointradius, 3 )
pygame.draw.circle(screen, blue, ((width_2),height_center), pointradius, 3 )
if onecircle == True:
radius = circle1(radius,centerradius)
elif twocircles == True:
radius = circle1(radius,centerradius)
radius2 = circle2(radius2, centerradius)
# 3. update the display
pygame.display.update()
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()):
I am attempting to create a game in which a block moves back and forth until the player presses space. Upon which, the block jumps to the next line up and stops.
Currently i am having problems with the collision code.
The error being thrown up by the shell is:
if doRectsOverlap(j['rect'], floors['line']):
TypeError: list indices must be integers, not str
I am stuck with understanding where my code has gone wrong. My knowledge of how python works is very limited.
There is also code i have commented out to do with the floor moving dowards when the player jumps. it has been commented out until i can get the collisions working, but still included
Code Below:
import pygame, sys, time
from pygame.locals import *
def doRectsOverlap(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
# Check if a's corners are inside b
if ((isPointInsideRect(a.left, a.top, b)) or
(isPointInsideRect(a.left, a.bottom, b)) or
(isPointInsideRect(a.right, a.top, b)) or
(isPointInsideRect(a.right, a.bottom, b))):
return True
return False
def isPointInsideRect(x, y, rect):
if (x > rect.left) and (x < rect.right) and (y > rect.top) and (y < rect.bottom):
return True
else:
return False
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
WINDOWWIDTH = 480
WINDOWHEIGHT = 800
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Jumper')
#Directions
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2
STILL = 5
#blocks location for jumping
#BLOCKLOCY = 700
#Binary for stopping movement
#STOPPER = 0
MOVESPEED = 1
# set up the colors
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
j = {'rect':pygame.Rect(240, 700, 20, 20), 'color':GREEN, 'dir':LEFT, 'jump':STILL}
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
# run the game loop
while True:
# check for the QUIT event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# draw the black background onto the surface
windowSurface.fill(BLACK)
# move the block data structure
if j['dir'] == LEFT:
j['rect'].left -= MOVESPEED
if j['dir'] == RIGHT:
j['rect'].left += MOVESPEED
if j['jump'] == UP:
j['rect'].bottom -= MOVESPEED
#BLOCKLOCY -= MOVESPEED
if j['rect'].left < 0:
j['dir'] = RIGHT
if j['rect'].left > WINDOWWIDTH-j['rect'].width:
j['dir'] = LEFT
if event.type == KEYDOWN:
if event.key == K_SPACE:
j['jump'] = UP
if doRectsOverlap(j['rect'], floors['line']):
j['jump'] = STILL
#Floor controll code for moving level - not working currently
# for f in floors:
#if f['dir'] == DOWN:
# f['line'].y += MOVESPEED
# if event.type == KEYDOWN:
# if event.key == K_SPACE:
# f['dir'] = DOWN
# if f['line'].top == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
#if f['line'].bottom == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
# draw the block onto the surface
pygame.draw.rect(windowSurface, j['color'], j['rect'])
pygame.draw.rect(windowSurface, f['color'], f['line'])
# draw the window onto the screen
pygame.display.update()
mainClock.tick(40)
You are creating floors as a list:
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
So when you call:
if doRectsOverlap(j['rect'], floors['line']):
j['jump'] = STILL
You're message is telling you that you need an index as an int:
for n in range(len(floors)):
if doRectsOverlap(j['rect'], floors[n]['line']):
j['jump'] = STILL