Clicking on images with PyGame - python-2.7

I am currently developing a game using Python and PyGame. I have made image sprites for the main option buttons, but I cannot seem to figure out how to make the images clickable which will take me to a different screen. Source code:
import os
import sys
import pygame
import time
class Colors:
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
dark_red = (102, 0, 0)
grey = (128, 128, 128)
dark_grey = (51, 51, 51)
class Variables:
screen_w = 1000
screen_h = 600
battleButton = pygame.image.load("Images/battle_button.png")
shopButton = pygame.image.load("Images/shop_button.png")
saveButton = pygame.image.load("Images/save_button.png")
equippedItem = pygame.image.load("Images/equipped.png")
creditsButton = pygame.image.load("Images/credits_button.png")
baseballBat = pygame.image.load("Images/baseball_bat.png")
baseballBat = pygame.transform.scale(baseballBat, (250, 250))
playerHealthMax = 100
playerHealthMin = 0
playerHealth = playerHealthMax
playerCash = 0
pygame.font.init()
gameFont = pygame.font.SysFont("Tweaky", 70)
title = gameFont.render("Causatum", 1, (Colors.black))
mainFont = pygame.font.SysFont("Arial Rounded MT Bold", 50)
equippedWeap = mainFont.render("Equipped", 1, (Colors.black))
cash = mainFont.render("Cash: ${}".format(playerCash), 1,
(Colors.black))
health = mainFont.render("Health: {}".format(playerHealth), 1,
(Colors.black))
gameVersion = mainFont.render("v1.0.0", 1, (Colors.black))
screen = pygame.display.set_mode((Variables.screen_w, Variables.screen_h))
pygame.display.set_caption("Causatum")
screen.fill(Colors.black)
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(Colors.grey)
screen.blit(Variables.battleButton, (0, 170))
screen.blit(Variables.shopButton, (0, 240))
screen.blit(Variables.saveButton, (0, 310))
screen.blit(Variables.title, (330, 0))
screen.blit(Variables.equippedItem, (645, 250))
screen.blit(Variables.baseballBat, (735, 230))
screen.blit(Variables.equippedWeap, (723, 215))
screen.blit(Variables.creditsButton, (0, 380))
screen.blit(Variables.cash, (0, 50))
screen.blit(Variables.health, (0, 0))
screen.blit(Variables.gameVersion, (905, 0))
pygame.display.flip()
Any kind of help is appreciated. Thanks.

Try something like this:
#in 'Variables' add this line
battleButton_rect = battleButton.get_rect(centerx = 0, centery = 170)
#new function, outside any classes
def collide(mouseX, mouseY, rect): #new function for checking the collision of the mouse with a button
return (mouseX >= rect.x-rect.width/2 and mouseX <= rect.x+rect.width/2 and mouseY >= rect.y-rect.height/2 and mouseY <= rect.y+rect.height/2)
# in 'while running'
if pygame.mouse.get_pressed()[0]: #0 for left button, 1 for right, 2 for middle
mouse_pos = pygame.mouse.get_pos()
if collide(mouse_pos[0], mouse_pos[1], Variables.battleButton_rect):
#code for battle button clicked here
#replace
screen.blit(Variables.battleButton, (0, 170))
#with
screen.blit(Variables.battleButton, Variables.battleButton_rect)
This, of course, is only for the battle button. You need to add a Rect for every button you use. Also, I would suggest making a button class with the collision function inside and having an array of those buttons that you can iterate through without convoluting your code. But the above is a quick and dirty solution.
Hope this helps!

Related

Issue with script using Pygame

I'm writing a small game in my spare time. This is what I have so far:
from pygame import * #import relevant modules
from PIL import Image
import os, sys
init() #initialise
class sprite:
def __init__(self, object, x = 0, y = 0, w = 0, h = 0):
self.image = image.load(object).convert()
self.posx = x
self.posy = y
self.position = ((x, y, w, h))
def resize(self, sh, sw):
self.image = transform.scale(self.image, (sh, sw))
return self.image
def move(self, window, background, right, down):
self.posx = x + right
self.posy = y + down
window.blit(background, self.position, self.position)
self.position.move(right, down)
window.blit(self, self.position)
window.update()
os.chdir('C:\\Users\\alesi\\Documents\\Pygame\\Project\\') #current folder change
win = display.set_mode((736, 552))#load window
Clock = time.Clock() #handy clock
background = image.load('background.jpg').convert()#load images
player = sprite('ball.png', 350, 275, 20, 20)
player = player.resize(20, 20)
win.blit(background, (0, 0))
win.blit(player, (350, 275))
display.update()
while True:
event.pump()
keys = key.get_pressed()
if keys[K_ESCAPE]:
sys.exit()
elif keys[K_RIGHT]:
player.move(win, background, 20, 0)
elif keys[K_LEFT]:
player.move(win, background, -20, 0)
elif keys[K_DOWN]:
player.move(win, background,0, 20)
elif keys[K_UP]:
player.move(win, background, 0, -20)
In short, it should create an object on a background and allow you to move the object using the arrow keys. However, I get the error:
C:\Users\alesi\Documents\Pygame\Project>python2 game2.py
Traceback (most recent call last):
File "game2.py", line 51, in <module>
player.move(win, background, -20, 0)
AttributeError: 'pygame.Surface' object has no attribute 'move'
I'm struggling to understand why my player instance of the sprite class is not recognising the move method. Also, I'm confused by why during the win.blit() function, I have to give the argument player instead of player.image, the attribute which I've stored the image.
Any advice would be appreciated.
In code
def resize(self, sh, sw):
self.image = transform.scale(self.image, (sh, sw))
return self.image
you returns image which is Surface instance - so in line
player = player.resize(20, 20)
you replace sprite instance with Surface instance
But you don't have to assign it to player again.
Do:
def resize(self, sh, sw):
self.image = transform.scale(self.image, (sh, sw))
# without return
# without player =
player.resize(20, 20)
After that player.move(...) will work again.
And again you will have to use player.image in blit()

Pygame, my sprite looks wierd

I'm working on this project for Literature class and I'm planning on making a game with pygame based of this book we were reading.
Here's the code:
import pygame, sys
from pygame.locals import *
pygame.init()
FPS = 30
fpsClock = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
pygame.display.set_caption('Animation')
WHITE = (255, 255, 255)
romeo = pygame.image.load('rome.png.png')
romeo = pygame.transform.scale(romeo, (50, 50))
romeox = 10
romeoy = 10
while True: # the main game loop
keys = pygame.key.get_pressed()
if keys[K_RIGHT]:
romeox += 5
if keys[K_LEFT]:
romeox -= 5
if keys[K_UP]:
romeoy -=5
if keys[K_DOWN]:
romeoy += 5
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
DISPLAYSURF.blit(romeo, (romeox, romeoy))
pygame.display.update()
fpsClock.tick(FPS)
Unfortunately, the sprite seems to leave a trail of it's own copies while it moves.
Here
Please help!
Seems like you forgot to clear the screen every iteration
# Fill surface with black color
DISPLAYSURF.fill((0, 0, 0))
Insert it above the line that blits the sprite onto the screen.

one entrance for loop in threading

I am using pyqt4 , python2.7. opencv3 , raspbian
I create Function with name Vision_thread()to search faces in every frame. and create funcation with name start_thread() to execute Vision_thread()Function by thread. look here:
def start_thread():
t1 = threading.Thread(target=Vision_thread)
t1.start()
#t1.join()
now I call Funcation by button created by PYqt4 as way:
self.pushButtonStart.setText(_translate("MainWindow", "Start Vision", None))
# program event click for start Vision button
self.pushButtonStart.clicked.connect(start_thread)
my problem is : when click on button . the loop in function Vision_thread() execute for first entrance only . and do not continuous .
but when I write:
t1 = threading.Thread(target=Vision_thread())
insted of
t1 = threading.Thread(target=Vision_thread)
the function Vision_thread() execute without any problem . but this is no thread .
what is problem??????
Vision_thread() code is :
def Vision_thread():
print("Vision")
print (search)
GPIO.output(32,True)
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
image = frame.array
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2)
face = gray[y:y + h, x:x + w]
face_resize = cv2.resize(face, (width, height))
#Try to recognize the face
prediction = model.predict(face_resize)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 3)
x_left=160
if prediction[1]<500:
cv2.putText(image,'%s - %.0f' % (names[prediction[0]],prediction[1]),(x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
if names[prediction[0]]==search:
x_left = x-width
x_right = width - w - x
sum_final=x_left+x_right
if x_left>180:
Left_thread()
if x_left<140:
Right_thread()
print "left={0}\nright={1}\nsum={2}".format(x_left, x_right,sum_final)
else:
cv2.putText(image,'not recognized',(x-10, y-10), cv2.FONT_HERSHEY_PLAIN,1,(0, 255, 0))
cv2.imshow('OpenCV', image)
key = cv2.waitKey(10)
rawCapture.truncate(0)
if key == 27:
GPIO.output(32,False)
break

Pygame: Movement Stops When Running a function twice [duplicate]

I have made a list of bullets and a list of sprites using the classes below. How do I detect if a bullet collides with a sprite and then delete that sprite and the bullet?
#Define the sprite class
class Sprite:
def __init__(self,x,y, name):
self.x=x
self.y=y
self.image = pygame.image.load(name)
self.rect = self.image.get_rect()
def render(self):
window.blit(self.image, (self.x,self.y))
# Define the bullet class to create bullets
class Bullet:
def __init__(self,x,y):
self.x = x + 23
self.y = y
self.bullet = pygame.image.load("user_bullet.BMP")
self.rect = self.bullet.get_rect()
def render(self):
window.blit(self.bullet, (self.x, self.y))
In PyGame, collision detection is done using pygame.Rect objects. The Rect object offers various methods for detecting collisions between objects. Even the collision between a rectangular and circular object such as a paddle and a ball can be detected by a collision between two rectangular objects, the paddle and the bounding rectangle of the ball.
Some examples:
pygame.Rect.collidepoint:
Test if a point is inside a rectangle
repl.it/#Rabbid76/PyGame-collidepoint
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(100, 100)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
point = pygame.mouse.get_pos()
collide = rect.collidepoint(point)
color = (255, 0, 0) if collide else (255, 255, 255)
window.fill(0)
pygame.draw.rect(window, color, rect)
pygame.display.flip()
pygame.quit()
exit()
pygame.Rect.colliderect
Test if two rectangles overlap
See also How to detect collisions between two rectangular objects or images in pygame
repl.it/#Rabbid76/PyGame-colliderect
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
rect1 = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
rect2 = pygame.Rect(0, 0, 75, 75)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
rect2.center = pygame.mouse.get_pos()
collide = rect1.colliderect(rect2)
color = (255, 0, 0) if collide else (255, 255, 255)
window.fill(0)
pygame.draw.rect(window, color, rect1)
pygame.draw.rect(window, (0, 255, 0), rect2, 6, 1)
pygame.display.flip()
pygame.quit()
exit()
Furthermore, pygame.Rect.collidelist and pygame.Rect.collidelistall can be used for the collision test between a rectangle and a list of rectangles. pygame.Rect.collidedict and pygame.Rect.collidedictall can be used for the collision test between a rectangle and a dictionary of rectangles.
The collision of pygame.sprite.Sprite and pygame.sprite.Group objects, can be detected by pygame.sprite.spritecollide(), pygame.sprite.groupcollide() or pygame.sprite.spritecollideany(). When using these methods, the collision detection algorithm can be specified by the collided argument:
The collided argument is a callback function used to calculate if two sprites are colliding.
Possible collided callables are collide_rect, collide_rect_ratio, collide_circle, collide_circle_ratio, collide_mask
Some examples:
pygame.sprite.spritecollide()
repl.it/#Rabbid76/PyGame-spritecollide
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((75, 75))
sprite1.image.fill((255, 0, 0))
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((75, 75))
sprite2.image.fill((0, 255, 0))
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
all_group = pygame.sprite.Group([sprite2, sprite1])
test_group = pygame.sprite.Group(sprite2)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sprite1.rect.center = pygame.mouse.get_pos()
collide = pygame.sprite.spritecollide(sprite1, test_group, False)
window.fill(0)
all_group.draw(window)
for s in collide:
pygame.draw.rect(window, (255, 255, 255), s.rect, 5, 1)
pygame.display.flip()
pygame.quit()
exit()
For a collision with masks, see How can I make a collision mask? or Pygame mask collision
See also Collision and Intersection
pygame.sprite.spritecollide() / collide_circle
repl.it/#Rabbid76/PyGame-spritecollidecollidecircle
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(sprite1.image, (255, 0, 0), (40, 40), 40)
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
sprite1.radius = 40
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((80, 89), pygame.SRCALPHA)
pygame.draw.circle(sprite2.image, (0, 255, 0), (40, 40), 40)
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
sprite2.radius = 40
all_group = pygame.sprite.Group([sprite2, sprite1])
test_group = pygame.sprite.Group(sprite2)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sprite1.rect.center = pygame.mouse.get_pos()
collide = pygame.sprite.spritecollide(sprite1, test_group, False, pygame.sprite.collide_circle)
window.fill(0)
all_group.draw(window)
for s in collide:
pygame.draw.circle(window, (255, 255, 255), s.rect.center, s.rect.width // 2, 5)
pygame.display.flip()
pygame.quit()
exit()
What does this all mean for your code?
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The position of the rectangle can be specified by a keyword argument. For example, the centre of the rectangle can be specified with the keyword argument center. These keyword arguments are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect for a list of the keyword arguments).
See *Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
You do not need the x and y attributes of Sprite and Bullet at all. Use the position of the rect attribute instead:
#Define the sprite class
class Sprite:
def __init__(self, x, y, name):
self.image = pygame.image.load(name)
self.rect = self.image.get_rect(topleft = (x, y))
def render(self):
window.blit(self.image, self.rect)
# Define the bullet class to create bullets
class Bullet:
def __init__(self, x, y):
self.bullet = pygame.image.load("user_bullet.BMP")
self.rect = self.bullet.get_rect(topleft = (x + 23, y))
def render(self):
window.blit(self.bullet, self.rect)
Use pygame.Rect.colliderect() to detect collisions between instances of Sprite and Bullet.
See How to detect collisions between two rectangular objects or images in pygame:
my_sprite = Sprite(sx, sy, name)
my_bullet = Bullet(by, by)
while True:
# [...]
if my_sprite.rect.colliderect(my_bullet.rect):
printe("hit")
From what I understand of pygame you just need to check if the two rectangles overlap using the colliderect method. One way to do it is to have a method in your Bullet class that checks for collisions:
def is_collided_with(self, sprite):
return self.rect.colliderect(sprite.rect)
Then you can call it like:
sprite = Sprite(10, 10, 'my_sprite')
bullet = Bullet(20, 10)
if bullet.is_collided_with(sprite):
print('collision!')
bullet.kill()
sprite.kill()
There is a very simple method for what you are trying to do using built in methods.
here is an example.
import pygame
import sys
class Sprite(pygame.sprite.Sprite):
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 20])
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = pos
def main():
pygame.init()
clock = pygame.time.Clock()
fps = 50
bg = [255, 255, 255]
size =[200, 200]
screen = pygame.display.set_mode(size)
player = Sprite([40, 50])
player.move = [pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN]
player.vx = 5
player.vy = 5
wall = Sprite([100, 60])
wall_group = pygame.sprite.Group()
wall_group.add(wall)
player_group = pygame.sprite.Group()
player_group.add(player)
# I added loop for a better exit from the game
loop = 1
while loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
loop = 0
key = pygame.key.get_pressed()
for i in range(2):
if key[player.move[i]]:
player.rect.x += player.vx * [-1, 1][i]
for i in range(2):
if key[player.move[2:4][i]]:
player.rect.y += player.vy * [-1, 1][i]
screen.fill(bg)
# first parameter takes a single sprite
# second parameter takes sprite groups
# third parameter is a do kill command if true
# all group objects colliding with the first parameter object will be
# destroyed. The first parameter could be bullets and the second one
# targets although the bullet is not destroyed but can be done with
# simple trick bellow
hit = pygame.sprite.spritecollide(player, wall_group, True)
if hit:
# if collision is detected call a function in your case destroy
# bullet
player.image.fill((255, 255, 255))
player_group.draw(screen)
wall_group.draw(screen)
pygame.display.update()
clock.tick(fps)
pygame.quit()
# sys.exit
if __name__ == '__main__':
main()
Make a group for the bullets, and then add the bullets to the group.
What I would do is this:
In the class for the player:
def collideWithBullet(self):
if pygame.sprite.spritecollideany(self, 'groupName'):
print("CollideWithBullet!!")
return True
And in the main loop somewhere:
def run(self):
if self.player.collideWithBullet():
print("Game Over")
Hopefully that works for you!!!
Inside the Sprite class, try adding a self.mask attribute with
self.mask = pygame.mask.from_surface(self.image)
and a collide_mask function inside of the Sprite class with this code:
def collide_mask(self, mask):
collided = False
mask_outline = mask.outline()
self.mask_outline = self.mask.outline()
for point in range(len(mask_outline)):
mask_outline[point] = list(mask_outline[point])
mask_outline[point][0] += bullet.x
mask_outline[point][1] += bullet.y
for point in range(len(self.mask_outline)):
self.mask_outline[point] = list(mask_outline[point])
self.mask_outline[point][0] += self.x
self.mask_outline[point][1] += self.y
for point in mask_outline:
for self_mask_point in self.mask_outline:
if point = self_mask_point:
collided = True
return collided

Pygame assiging to rect.attributes doesn't change the anything

From the documentation:
"Assigning to size, width or height changes the dimensions of the rectangle".
I have the following circle, assign a new attribute but no changes can be seen in circle. What am i doing wrong?
import pygame
from pygame.locals import *
pygame.init()
TV=pygame.display.set_mode((400,400))
pygame.display.set_caption("Rect")
c=pygame.draw.circle(TV,(0,100,0),(150,150),100,1)
pygame.draw.rect(TV,(100,0,0),c,1)
print c.size
c.size=(100,100)
print c.size
pygame.display.flip()
while True:
for e in pygame.event.get():
if e.type==QUIT:
pygame.quit()
You draw the circle on the screen surface. Every drawing function then returns a Rect, but:
The functions return a rectangle representing the bounding area of changed pixels.
To actually change the circle on the screen, you have to erase it first (draw something above it), then draw a new circle in the size you want.
Here's a simple example:
import pygame
from pygame.locals import *
pygame.init()
pygame.display.set_caption("Rect")
TV = pygame.display.set_mode((400,400))
c = pygame.draw.circle(TV, (0, 100, 0), TV.get_rect().center, 100, 1)
clock = pygame.time.Clock()
pygame.time.set_timer(USEREVENT, 250)
value = 10
run = True
while run:
for e in pygame.event.get():
if e.type == QUIT:
run = False
if e.type == USEREVENT:
c.inflate_ip(value, value)
if c.width > 260 or c.width < 200:
value *= -1
TV.fill(pygame.color.Color('Black'))
pygame.draw.circle(TV, (0, 100, 0), c.center, c.width/2, 1)
pygame.display.flip()
clock.tick(60)
pygame.quit()