Pygame .Rect won't "collide" with mouse - mouseevent

I am working on a simple game and with small circle "systems". I would like to be able to click each system so that I can do more with it later in game but I am having difficulty recognizing only a single click. I pass the randomly generated coords to a dictionary and then the collision for each rect should be checked with the mouse position but for some reason that is not working anymore. Any help is appreciated.
Here is some of the more relevent code.
for i in range(NumSystems):
SysSize = random.randint(3,SystemSize)
SysY = random.randint(SystemSize*2,GVPHEIGHT-SystemSize*2)
SysX = random.randint(OverLayWidth+SystemSize*2,WINWIDTH-SystemSize*2)
SysList[str('SysNum')+str(i)] = ((SysSize,(SysX,SysY)))
SysCoords[str('SysNum')+str(i)] = pygame.draw.circle(DISPLAYSURF, WHITE, (SysX,SysY), SysSize, 0)
pygame.display.update()
#time.sleep(.25)
#Code above is putting the random Coords into a dictionary.
while True:
MousePos=mouse.get_pos()
for event in pygame.event.get():
if event.type == QUIT:
pygame.QUIT()
sys.exit()
elif event.type == KEYDOWN:
# Handle key presses
if event.key == K_RETURN:
#Restarts the map
main()
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
SysClicky(MousePos)
if SysClicked == True:
print('Clicked System')
elif SysClicked == False:
print('Something Else Clicked')
def SysClicky(MousePos):
for i in range(NumSystems):
print('Made to the SysClicky bit')
if SysCoords['SysNum'+str(i)].collidepoint(MousePos):
SysClicked = True
print(SysClicked)
return SysClicked
else:
SysClicked = False
return SysClicked

I'm not clear on What SysList / SysX/Y, SysCoords are. Does it hold width,height of the items in SysCoords? If so, that's already in Rect()
below systems is your dict of Rects.
Here's the code:
def check_collisions(pos):
# iterate dict, check for collisions in systems
for k,v in systems.items():
if v.collidepoint(pos):
print("clicked system:", k)
return
print("clicked something else")
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1:
check_collisions(event.pos)
# render

Pygame rect objects have a collidepoint inbuilt method which takes a coordinate and returns a boolean based on collision. You can input the mouses coordinate into function like so:
MousePos=mouse.get_pos()
if mySurface.get_rect().collidepoint(MousePos):
doSomething()

Related

Pyplot modifies zoom when calling plt.draw()

I wrote a function that lets the user pick points from an image and returns the coordinates.
fig, ax = plt.subplots()
ax.imshow(pixel_array, cmap=plt.cm.hot)
plt.ion()
plt.show()
coords = get_points(fig, ax, 4)
where the function get_points is defined as
def get_points(fig, ax, n):
# Request the user to select n points in the figure fig on the axis ax
# If n is zero or negative, allow the selection of as many points as the user would like (minimum abs(n))
# If n is positive, allow only n points to be selected
if n > 0:
print('Select', n, 'points.')
elif n < 0:
print('Select at least', abs(n), 'points.')
else:
print('Select any number of points.')
print("Press 'Esc' to cancel the last point, or 'Enter' when complete.")
coords = []
handles = []
finished = False
def onClick(event):
nonlocal coords
if fig.canvas.manager.toolbar.mode != '': return # Don't take clicks involved in toolbar functions (pan, zoom, ...)
if event.inaxes!=ax: return # Don't take clicks outside the axes
if len(coords) < n or n <= 0:
coords.append((event.xdata, event.ydata))
handles.append(plt.scatter(event.xdata, event.ydata, s=100, c='red', marker='+'))
plt.draw()
else:
print('You have reached the maximum number of points for this operation.')
def onKey(event):
nonlocal finished
if event.key == 'escape':
if len(coords) > 0:
del coords[-1]
handles[-1].remove()
del handles[-1]
plt.draw()
elif event.key == 'enter':
if len(coords) >= abs(n):
finished = True
else:
print('You have selected', len(coords), 'out of a required', n, 'points.')
else:
print('You pressed "', event.key, '" which is unsupported', sep='')
cid = fig.canvas.mpl_connect('button_press_event', onClick)
cid2 = fig.canvas.mpl_connect('key_press_event',onKey)
while not finished:
plt.waitforbuttonpress(-1)
plt.disconnect(cid)
plt.disconnect(cid2)
return np.array(coords)
But the problem is that if I zoom or pan, then each time I select a point it resets the zoom/pan to the default. Is there any way to have it not do this? Is there a better way to do this overall?
Thanks in advance.

Is it Possible to set "Windows On-Screen Keyboard" as an input in sg.InputText field ( PySimpleGUI)?

Dears,
Is it Possible to set "Windows On-Screen Keyboard" as an input in sg.InputText field?
Thanks in advance
enter image description here ==> The Code
enter image description here ==> Desired Output
enter image description here ==> Split Keyboard to lines using "Menu Option"
Here's the demo code for you. Some functions for backspace key not built under PySimpleGUI, so tkinter code is required, like element.widget. The event for button 'OK' not included here. You can replace the keyboard string with yours.
import PySimpleGUI as sg
keys = ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"]
chars = ''.join(keys)
lines = list(map(list, keys))
lines[0] += ["\u232B", "Esc"]
col = [[sg.Push()] + [sg.Button(key) for key in line] + [sg.Push()] for line in lines]
layout = [
[sg.Text("Username"), sg.Push(), sg.Input(key="Username")],
[sg.Text("Password"), sg.Push(), sg.Input(key="Password")],
[sg.Push(), sg.Button("OK"), sg.Button("Cancel"),sg.Push(), sg.Button("Keyboard")],
[sg.pin(sg.Column(col, visible=False, expand_x=True, key='Column', metadata=False), expand_x=True)],
]
window = sg.Window('ACCESS', layout)
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, "Cancel"):
break
elif event == "Keyboard":
visible = window["Column"].metadata = not window["Column"].metadata
window["Column"].update(visible=visible)
elif event in chars:
element = window.find_element_with_focus()
if isinstance(element, sg.Input):
if element.widget.select_present():
element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
element.widget.insert(sg.tk.INSERT, event)
elif event == "\u232B":
element = window.find_element_with_focus()
if element.widget.select_present():
element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
else:
insert = element.widget.index(sg.tk.INSERT)
if insert > 0:
element.widget.delete(insert-1, insert)
window.close()
With MenuOption element, there's option enable_events, so tkinter call required here. There are three-line different keyboard, so each Column element for each keyboard line.
import PySimpleGUI as sg
def callback(var, index, mode):
window.write_event_value("Optionmenu", window['Optionmenu'].TKStringVar.get())
keys = ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"]
chars = ''.join(keys)
lines = list(map(list, keys))
lines[0] += ["\u232B", "Esc"]
layout = [
[sg.Text("Username"), sg.Push(), sg.Input(key="Username")],
[sg.Text("Password"), sg.Push(), sg.Input(key="Password")],
[sg.Push(), sg.Button("OK"), sg.Button("Cancel"),sg.Push(), sg.OptionMenu([f"Keyboard Line {i+1}" for i in range(3)], key='Optionmenu')],
[sg.Column([[sg.Push()] + [sg.Button(key) for key in line] + [sg.Push()]], key=f"Keyboard Line {i+1}", expand_x=True, visible=False) for i, line in enumerate(lines)],
]
window = sg.Window('ACCESS', layout, finalize=True)
window['Optionmenu'].TKStringVar.trace("w", callback) # enable events
keyboard = None
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, "Cancel"):
break
elif event == "Optionmenu":
if keyboard is not None:
window[keyboard].update(visible=False)
keyboard = values["Optionmenu"]
window[keyboard].update(visible=True)
elif event in chars:
element = window.find_element_with_focus()
if isinstance(element, sg.Input):
if element.widget.select_present():
element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
element.widget.insert(sg.tk.INSERT, event)
elif event == "\u232B":
element = window.find_element_with_focus()
if element.widget.select_present():
element.widget.delete(sg.tk.SEL_FIRST, sg.tk.SEL_LAST)
else:
insert = element.widget.index(sg.tk.INSERT)
if insert > 0:
element.widget.delete(insert-1, insert)
window.close()

Colliderect function not working in Pygame

So I am making a pong game in pygame while implementing oop. My problem is the colliderect function is giving me the error " ball_hitter object has no attribute 'colliderect'". I've used the colliderect function before but it's not working for me this time.
Code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption("Pong With Classes!")
#Variables
red = (255,0,0)
blue = (0,0,255)
black = (0,0,0)
clock = pygame.time.Clock()
#End of Variables
class ball_hitter:
def __init__(self,x,y,length,width,color):
self.x = x
self.y = y
self.length = length
self.width = width
self.color = color
self.left = False
self.right = False
def draw_ball_hitter(self):
screen.fill(black)
pygame.draw.rect(screen,self.color,(self.x,self.y,self.length,self.width))
#Paddle creation
paddle = ball_hitter(250,400,130,20,red)
#End of Paddle Creation
class thing_thats_being_hit:
def __init__(self,x,y,color):
self.x = x
self.y = y
self.radius = 27
self.color = color
self.speed_x = -4
self.speed_y = 4
def draw_googlyball(self):
pygame.draw.circle(screen,self.color,(self.x,self.y),self.radius)
def move(self):
self.x += self.speed_x
self.y += self.speed_y
#Ball Creation
ball = thing_thats_being_hit(200,50,blue)
#End of Ball Creation
#Paddle Collision
if paddle.colliderect(ball):
print("It Worked!")
#End Of Paddle Collision
ball.move()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
paddle.left = True
if event.key == pygame.K_RIGHT:
paddle.right = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
paddle.left = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
paddle.right = False
paddle.draw_ball_hitter()
ball.draw_googlyball()
if paddle.left == True:
paddle.x = paddle.x - 2
if paddle.right == True:
paddle.x = paddle.x + 2
if ball.x <= 0:
ball.speed_x*=-1
if ball.x >= 500:
ball.speed_x *= -1
if ball.y >= 500:
pygame.quit()
ball.move()
pygame.display.update()
clock.tick(100)
I would appreciate it if someone could give me a fixed code and explain is to me.
See How do I detect collision in pygame?. colliderect is a method of pygame.Rect. Therefore you need to create pygame.Rect objects. Also you have to do the collision test in the application loop instead of before the application loop:
while True:
# [...]
paddle_rect = pygame.Rect(paddle.x, paddle.y, paddle.width, paddle. length)
ball_rect = pygame.Rect(ball.x - ball.radius, ball.y - ball.radius,
ball.radius * 2, ball.radius * 2)
if paddle_rect.colliderect(ball_rect):
print("It Worked!")

I'm making a code with pygame in oop and I'm having trouble making one of my methods work

Basically, I am making a code that uses oop and pygame together. It draws 4 rectangles in the corners of the screen and gives each rectangle a name. I have to ask the user the name of one of the rectangles and change that rectangles color randomly.
Code:
import random
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption("BOOGABOOGA")
blue = (0,0,255)
red = (255,0,0)
green = (0,255,0)
white = (255,255,255)
random = [blue,red,green,white]
class Rectangle:
def __init__(self,name,color,x,y,width,height,thickness):
self.name = name
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.thickness = thickness
def coolboymethoddraw(self):
pygame.draw.rect(screen,self.color,(self.x,self.y,self.width,self.height),self.thickness)
recty1 = Rectangle("YOYO",blue,50,50,50,50,0)
recty2 = Rectangle("BABYBOOGA",blue,450,450,50,50,0)
recty3 = Rectangle("ChotaBEAM",blue,0,450,50,50,0)
recty4 = Rectangle("CHOTAJAGGU",blue,450,0,50,50,0)
jaggu = [recty1,recty2,recty3,recty4]
recty3.coolboymethoddraw()
recty1.coolboymethoddraw()
recty4.coolboymethoddraw()
recty2.coolboymethoddraw()
def change_color(self):
print("Give me the name of 1 of the 4 rectangles!")
x = input()
for chota in jaggu:
if x == chota.name:
l = random.choice(random)
chota.color = l
recty1.change_color()
recty2.changecolor()
recty3.change_color()
recty4.change_color()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
pygame.display.update()
I would appreciate an answer and why it wasn't working. Thanks!
First of all move your method change_color inside the class Rectangle.
class Rectangle:
def __init__(self,name,color,x,y,width,height,thickness):
self.name = name
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.thickness = thickness
def coolboymethoddraw(self):
pygame.draw.rect(screen,self.color,(self.x,self.y,self.width,self.height),self.thickness)
def change_color(self):
print("Give me the name of 1 of the 4 rectangles!")
x = input()
for chota in jaggu:
if x == chota.name:
l = random.choice(random)
chota.color = l
Then you need to move the draw methods inside the main loop, otherwise the rectangles will not be drawn.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
recty3.coolboymethoddraw()
recty1.coolboymethoddraw()
recty4.coolboymethoddraw()
recty2.coolboymethoddraw()
pygame.display.update()
Dont name your list of colors random because you import a package called random. Name the list something like colors_list
You dont need to call the change_color method for all 4 rectangles because inside of this method you go through a list of your 4 rectangles already.
There is also a problem in the change_color method. You need to call the method inside the main loop as well, but because of the print statement and the input it will end in an ifinite loop.

Error while validating User Input in Python

I am having problem validating the user input (I am asking user if they wish to continue with the program of calculating factorial). The code is as follows: (User input validation is towards the end of the main function and I have not included the factorial function)
def main():
valid_inp = False
usr_continue = True
while usr_continue:
while valid_inp == False:
usr_inp = int(input('Please ENTER a number: '))
if usr_inp < 0:
print('ERROR, INVALID INPUT')
else:
valid_inp = True
continue
result = factorial(usr_inp)
print(str(result) + '\n')
con_inp = str(input('Would you like to continue ? '))
if con_inp == 'Y' or con_inp == 'y':
usr_continue
elif con_inp == 'N' or con_inp == 'n':
print('Goodbye...')
break
main()
Make a function that only returns on valid input. Use an exception handler to deal with bad integer input, then validate the integer is the range you want:
from math import factorial
def get_nonnegative_integer(prompt):
while True:
try:
val = int(input(prompt)) # bad input for int such as "abc" will raise ValueError
if val >= 0: # good input will be range-checked
return val
else:
print('enter a number >= 0')
except ValueError:
print('invalid input for integer')
def main():
while True:
usr_inp = get_nonnegative_integer('Please enter a number: ')
result = factorial(usr_inp)
print(result)
con_inp = input('Would you like to continue(Y/n)? ').upper() # default Yes
if con_inp.startswith('N'):
print('Goodbye...')
break
main()