circle inside a rect with a button click - python-2.7

I am trying to create a game and i have to make this plexus made of buttons. Every time the player clicks the button, it should appear a small circle inside the pressed button. I tried to make a draw_circle function but when i place it on the action variable inside the buttons, I get this errror. Global name x is not defined.
import pygame
pygame.init()
display_width = 900
display_height = 600
black = (0,0,0)
white = (255,255,255)
red = (250,0,0)
green = (0,250,0)
bright_red =(200,0,0)
bright_green = (0,200,0)
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("A MATH'S GAME")
def draw_circle():
pygame.draw.circle(gameDisplay,black,(x,y),100)
def button(msg,x,y,w,h,ic,ac,action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac,(x,y,w,h))
if click[0] == 1 and action != None:
action()
else:
pygame.draw.rect(gameDisplay, ic,(x,y,w,h))
smallText = pygame.font.SysFont("comicsansms",20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
gameDisplay.blit(textSurf, textRect)
def text_objects(text, font):
textSurface = font.render(text, True, black)
return textSurface, textSurface.get_rect()
def messgae_display(text):
largeText = pygame.font.Font("Arial",60)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((display_width/2),(display_height/2))
gameDisplay.blit(TextSurf, TextRect)
pygame.display.update()
def quitgame():
pygame.quit()
quit()
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
largeText = pygame.font.SysFont("comicsansms",115)
TextSurf, TextRect = text_objects("A math's game", largeText)
TextRect.center = ((display_width/2),(display_height/2))
gameDisplay.blit(TextSurf, TextRect)
button("GO!",150,450,100,50,green,bright_green,draw_circle)
button("Quit",550,450,100,50,red,bright_red,quitgame)
pygame.display.update()
def game_loop():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
largeText = pygame.font.SysFont("comicsansms",50)
TextSurf, TextRect = text_objects("A math's game", largeText)
TextRect.center = ((display_width/2),100)
gameDisplay.blit(TextSurf, TextRect)
button(None,200,250,50,50,bright_red,red,None)
button(None,200,300,50,50,bright_red,red,None)
button(None,200,350,50,50,bright_red,red,None)
button(None,200,400,50,50,bright_red,red,None)
button(None,200,450,50,50,bright_red,red,None)
button(None,200,500,50,50,bright_red,red,None)
button(None,250,250,50,50,bright_red,red,None)
button(None,250,300,50,50,bright_red,red,None)
button(None,250,350,50,50,bright_red,red,None)
button(None,250,400,50,50,bright_red,red,None)
button(None,250,450,50,50,bright_red,red,None)
button(None,250,500,50,50,bright_red,red,None)
button(None,300,250,50,50,bright_red,red,None)
button(None,300,300,50,50,bright_red,red,None)
button(None,300,350,50,50,bright_red,red,None)
button(None,300,400,50,50,bright_red,red,None)
button(None,300,450,50,50,bright_red,red,None)
button(None,300,500,50,50,bright_red,red,None)
button(None,350,250,50,50,bright_red,red,None)
button(None,350,300,50,50,bright_red,red,None)
button(None,350,350,50,50,bright_red,red,None)
button(None,350,400,50,50,bright_red,red,None)
button(None,350,450,50,50,bright_red,red,None)
button(None,350,500,50,50,bright_red,red,None)
button(None,400,250,50,50,bright_red,red,None)
button(None,400,300,50,50,bright_red,red,None)
button(None,400,350,50,50,bright_red,red,None)
button(None,400,400,50,50,bright_red,red,None)
button(None,400,450,50,50,bright_red,red,None)
button(None,400,500,50,50,bright_red,red,None)
button(None,450,250,50,50,bright_red,red,None)
button(None,450,300,50,50,bright_red,red,None)
button(None,450,350,50,50,bright_red,red,None)
button(None,450,400,50,50,bright_red,red,None)
button(None,450,450,50,50,bright_red,red,None)
button(None,450,500,50,50,bright_red,red,None)
button(None,500,250,50,50,bright_red,red,None)
button(None,500,300,50,50,bright_red,red,None)
button(None,500,350,50,50,bright_red,red,None)
button(None,500,400,50,50,bright_red,red,None)
button(None,500,450,50,50,bright_red,red,None)
button(None,500,500,50,50,bright_red,red,None)
button(None,550,250,50,50,bright_red,red,None)
button(None,550,300,50,50,bright_red,red,None)
button(None,550,350,50,50,bright_red,red,None)
button(None,550,400,50,50,bright_red,red,None)
button(None,550,450,50,50,bright_red,red,None)
button(None,550,500,50,50,bright_red,red,None)
button(None,600,250,50,50,bright_red,red,None)
button(None,600,300,50,50,bright_red,red,None)
button(None,600,350,50,50,bright_red,red,None)
button(None,600,400,50,50,bright_red,red,None)
button(None,600,450,50,50,bright_red,red,None)
button(None,600,500,50,50,bright_red,red,None)
button(None,650,250,50,50,bright_red,red,None)
button(None,650,300,50,50,bright_red,red,None)
button(None,650,350,50,50,bright_red,red,None)
button(None,650,400,50,50,bright_red,red,None)
button(None,650,450,50,50,bright_red,red,None)
button(None,650,500,50,50,bright_red,red,None)
pygame.display.update()
pygame.init()
game_intro()

In the line button("GO!",150,450,100,50,green,bright_green,draw_circle) you aren't giving draw_circle a value for x or y, so they are, in fact, not defined. You need to pass these down to to the draw_circle function.
Inside of your button function, pass the arguments down to draw_circle like:
if click[0] == 1 and action != None:
action(x, y)

Related

Each blitted image in list disappear instead of remaining on screen. I wanted to fill up the whole screen with image as it blits on random locations

import pygame
import random
pygame.init()
screen = pygame.display.set_mode((476,800))
clock = pygame.time.Clock()
win = pygame.display.set_mode((500, 600))
pygame.display.set_caption("DOGGO GAME")
dogimg = pygame.image.load('dog.png')
*doglist will contain the image rects so that multiple images/entities will fill the screen
doglist = []
dogx = []
dogy = []
blot triggers the creation of element(dog image rect = dogimg)
BLOT = pygame.USEREVENT
pygame.time.set_timer(BLOT, 500)
drawdog blits the images in the doglist
def drawdog(doglist):
for dog in doglist:
screen.blit(dogimg, new_dog)
run = True
while run:
#pygame.time.delay(50)
win.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == BLOT:
dogimg = pygame.image.load('dog.png')
dogranx = random.randint(50,200)
dograny = random.randint(50,450)
new_dog = dogimg.get_rect(midtop=(dogranx, dograny))
doglist.append(new_dog)
print(doglist)
drawdog(doglist)
pygame.display.update()
clock.tick(1)
pygame.quit()
I was able to correct it by replacing:
for dog in doglist
with
for new_dog in doglist
In the former, I was using extend. I changed it to append and used the latter code, and it worked.

Optimizing Keyboard Input in Pygame

I am creating a very simple game using the pygame library in which the player moves a square around the screen with the arrow keys. Unfortunately, the response of the controls are proving to be a problem.
The controls work fine until you switch direction e.g. left to right. When the player switches direction, the square the player is controlling jars to a halt.
The code for the controls looks like this in my game:
def move(self, event):
speed = 6
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.rect.x -= speed
if event.key == pygame.K_RIGHT:
self.rect.x += speed
if event.key == pygame.K_DOWN:
self.rect.y += speed
if event.key == pygame.K_UP:
self.rect.y -= speed
This method is located in a class called Block (I stole Block from the pygame docs) that just makes a sprite for the player alongside providing movement.
The function move() is actually called inside the main.py file like this:
while going:
clock.tick(60)
# event handling
for event in pygame.event.get():
if event.type == QUIT:
going = False
# controller input
player.move(event)
Where player is an instance of the Block class and event is just an item from the event queue of my game.
I tried using the pygame.key.get_pressed function (which did work better) but I would rather use the pygame.KEYDOWN locals alternatively because it returns the key presses as events in the event queue rather than booleans returned from a list.
If you are more investigative than your average joe you can take a look at the "full" game here: https://github.com/catmes/Project_React
You will need pygame 1.9.2 and python 2.7. Keep in my mind that the game itself is more a learning exercise so don't surprised when you see bad code (that will be fixed later of course ;) ).
Thanks for stopping by and giving this question a peek, I do appreciate your time.
I've tried out a smooth way to move around a player that works pretty well. It basically keeps track of the key presses in a list and moves the player based on the last key pressed. When you press a key it'll add a speed variable at the first position in the list, and when you release the key it'll remove that variable. In the update method you'll add the first speed variable of the list to corresponding x and y value.
import pygame
pygame.init()
screen = pygame.display.set_mode((720, 480))
class Player(pygame.sprite.Sprite):
def __init__(self):
super(Player, self).__init__()
self.rect = pygame.Rect((0, 0), (32, 32))
self.image = pygame.Surface((32, 32))
self.image.fill((255, 255, 255))
self.velocity = [0, 0] # It's current velocity.
self.speed = 4 # The speed the player will move.
self.dx = [] # Keeps track of the horizontal movement.
self.dy = [] # Keeps track of the vertical movement.
def update(self):
try:
self.rect.x += self.dx[0] # Index error if the list is empty.
except IndexError:
self.rect.x += 0
try:
self.rect.y += self.dy[0] # Index error if the list is empty.
except IndexError:
self.rect.y += 0
player = Player()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
raise SystemExit
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player.dx.insert(0, -player.speed)
elif event.key == pygame.K_d:
player.dx.insert(0, player.speed)
elif event.key == pygame.K_w:
player.dy.insert(0, -player.speed)
elif event.key == pygame.K_s:
player.dy.insert(0, player.speed)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a:
player.dx.remove(-player.speed)
elif event.key == pygame.K_d:
player.dx.remove(player.speed)
elif event.key == pygame.K_w:
player.dy.remove(-player.speed)
elif event.key == pygame.K_s:
player.dy.remove(player.speed)
player.update()
screen.fill((0, 0, 0))
screen.blit(player.image, player.rect)
pygame.display.update()
# print player.dx, player.dy # Uncomment to see what's happening in action!

Pygame Collision with Changing sprites

Alright,
I've looked everywhere and still can't figure out PyGame collisions. I have two sprites: A lander and a moon surface. The moon is an uneven surface with a transparent background, while the lander is a sprite that changes through images with L,D,UP keypresses.
I'm doing something wrong when it comes to collision detection. Otherwise, everything in my program is going swimmingly
This is my lander class:
class ShipClass(pygame.sprite.Sprite):
def __init__(self, image_file, position):
pygame.sprite.Sprite.__init__(self)
self.imageMaster = pygame.image.load(image_file)
self.image = self.imageMaster
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.imageMaster)
self.rect.topleft = position
## This doesn't work
# def checkCollision(self, Mask):
# if Mask.overlap_area
def update(self):
self.rect = self.image.get_rect()
And this is my lunar surface class:
class MoonSurface(pygame.sprite.Sprite):
def __init__(self, image_file, position):
pygame.sprite.Sprite.__init__(self)
self.imageMaster = pygame.image.load(image_file).convert_alpha()
self.image = self.imageMaster
self.rect = self.image.get_rect()
self.rect.topleft = position
What do I need to add to this so that while in my game if the lander hits the moon it sets variable stop to 1 and crash to 1? I plan on also adding landing pads with the MoonSurface class and when it hits them only sets stop to 1.
My sprite is moved as follows:
speed = [0,0]
position = [width-524,height-718]
gravity = 0.05
StartingFuel = 100
done = False
while not done:
event = pygame.event.poll()
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == pygame.KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
else:
lander = ShipClass('lander.png', position)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
lander = ShipClass('landerLeft.png', position)
# lander.set_colorkey(BLACK)
speed[0] += 0.3
fuel -= 1
if keys[pygame.K_RIGHT]:
lander = ShipClass('landerRight.png', position)
# lander.set_colorkey(BLACK)
speed[0] -= 0.3
fuel -= 1
if keys[pygame.K_UP]:
lander = ShipClass('landerUp.png', position)
# lander.set_colorkey(BLACK)
speed[1] -= 0.4
fuel -= 1
speed[1] += gravity
position[0] += speed[0]
position[1] += speed[1]
if position[0] < 0:
position[0] = width
elif position[0] > width:
position[0] = 0
screen.blit(lander.image, position)
It looks like you want to check if the two objects overlap. Luckily Pygame has a built- in function colliderect which checks if two rectangles are overlapping. I've put it into a class method here, as I saw your objects had Pygame rectangle variables named rect:
def overlaps (self, other_rect):
return self.rect.colliderect(other_rect)
Here's the documentation: pygame.Rect

How to reset time back to 0 in pygame?

I am trying to make a game in pygame where you need to click the image to gain a score.My program works but i still need to fix 2 bugs:
Bug 1
When the user presses 'c' that is play again,the **time does not reset back to 0. I want it back to 0 , so that every 10 seconds the game gets over and you cant play it anymore.
Bug 2
The time starts even if the user does not press 'c' , i.e to play game.So by the time user reads the rules (assuming they took 5 seconds to read rules) , and then they press 'c' they only have 5 more seconds to play.I want it to do it so that only when the user presses 'c' the game time starts.
This is my game run up source code:
def runGame():
#Initial score is 0
score=0
gameExit = False
gameOver = False
while not gameExit:
while gameOver == True:
#Game Over message
gameDisplay.fill(black)
message_to_screen("Game over",
red,
y_displace=-50,
size="large")
message_to_screen("Press C to play again or Q to quit.",
white,
y_displace=50,
size="medium")
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
if event.key == pygame.K_c: #If user press 'c' , game starts
gameLoop()
gameDisplay.fill((white))
#Possible Error from here
# ~~~~~~~~~~~~~~~
#My time function
time=pygame.time.get_ticks()/1000
if time==11: #Checks if time hit 10 (i took as 11 as it should complete the 10th second)
global time
global score
score=0
time=0
gameOver=True
#~~~~~~~~~~~~~ Till here
for event in pygame.event.get():
if event.type==pygame.QUIT:
running=False
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == LEFT:
# Set the x, y postions of the mouse click
x, y = event.pos
if foodrect.collidepoint(x, y):
foodrect.center=(random.randint(5,1060),random.randint(5,700))
print "New Position: ",foodrect.center
score+=1
continue
gameDisplay.blit(foodimg,foodrect)
showtime=font.render("Time: "+str(time),0,(0,0,0))
gameDisplay.blit(showtime,(950,10))
scoredisplay(score)
pygame.display.update()
My Game Loop
def gameLoop():
clock.tick(FPS)
runGame()
pygame.quit()
quit()
gameLoop()
Full Code
As requested by Herman Yanush.
import pygame
import time
import random
pygame.init()
foodimg=pygame.image.load("food.png")
foodrect=foodimg.get_rect()
#Colours
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
LEFT =1
#Game Display
display_width = 1080
display_height = 720
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Click It! ~ Snapnel Productions')
gameDisplay.fill((white))
font=pygame.font.SysFont("Arial",30)
#Clock
clock = pygame.time.Clock()
FPS = 30
cellSize=10
#Font Size
exsmallfont = pygame.font.SysFont("comicsansms", 17)
smallfont = pygame.font.SysFont("comicsansms", 25)
medfont = pygame.font.SysFont("comicsansms", 50)
largefont = pygame.font.SysFont("comicsansms", 80)
#The score function - displays the score on top right
def scoredisplay(scoredef=0):
text=smallfont.render("Score :%s" %(scoredef) ,True ,white)
gameDisplay.blit(text,[0,0])
def scoredisplay1(musicname):
text=exsmallfont.render("Now Playing :%s" %(musicname) ,True ,white)
gameDisplay.blit(text,[690,5])
#Starting Of the game
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key ==pygame.K_c:
intro = False
if event.key ==pygame.K_q:
pygame.quit()
quit()
gameDisplay.fill(black)
#Game Initial display message
message_to_screen("Click It!",
red,
-200,
size="large")
message_to_screen("This Game is created by Shrapnel",
white,
-30,
size="small")
message_to_screen(" the food to gain a point!",
white,
10,
size="small")
message_to_screen("Press 'C' to play the game or 'Q' to quit.",
white,
150,
size="small")
pygame.display.update()
clock.tick(15)
#Text Size
def text_objects(text,color, size):
if size=="small":
textSurface=smallfont.render(text, True ,color)
elif size=="medium":
textSurface=medfont.render(text, True ,color)
elif size=="large":
textSurface=largefont.render(text, True ,color)
return textSurface,textSurface.get_rect()
#Message to screen
def message_to_screen(msg,color,y_displace=0,size="small"):
textSurf,textRect=text_objects(msg,color,size)
textRect.center = (display_width / 2),(display_height / 2)+y_displace
gameDisplay.blit(textSurf,textRect)
#Score Display
def scoredisplay(scoredef=0):
text=smallfont.render("Score :%s" %(scoredef) ,True ,black)
gameDisplay.blit(text,[0,0])
score=0
global a
a=10
#print score
def runGame():
score=0
gameExit = False
gameOver = False
thing_startx = random.randrange(0,display_width)
thing_starty = -600
thing_speed = 7
thing_width = 100
thing_height = 100
while not gameExit:
deadZones=[]
while gameOver == True:
#Game Over message
gameDisplay.fill(black)
message_to_screen("Game over",
red,
y_displace=-50,
size="large")
message_to_screen("Press C to play again or Q to quit.",
white,
y_displace=50,
size="medium")
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
if event.key == pygame.K_c:
gameLoop()
gameDisplay.fill((white))
time=pygame.time.get_ticks()/1000
if time==11:
global time
global score
score=0
time=0
gameOver=True
#print score
for event in pygame.event.get():
if event.type==pygame.QUIT:
running=False
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == LEFT:
# Set the x, y postions of the mouse click
x, y = event.pos
if foodrect.collidepoint(x, y):
foodrect.center=(random.randint(5,1060),random.randint(5,700))
print "New Position: ",foodrect.center
score+=1
continue
gameDisplay.blit(foodimg,foodrect)
showtime=font.render("Time: "+str(time),0,(0,0,0))
gameDisplay.blit(showtime,(950,10))
#scoredisplay(score)
pygame.display.update()
def gameLoop():
clock.tick(FPS)
runGame()
pygame.quit()
quit()
game_intro()
gameLoop()
Thanks in advance to help.
I think I might have a solution that at least I use. While sometimes it is nice to use pygame.time.get_ticks, there is an easier solution. Before your while loop set a variable called frame to 0. Then at the end of your while loop type:
if gameEnd == True:
frame=0
score=0
else:
frame+=1
Then all you have to do is only draw the picture when frame>0. You can also easily manipulate frame. Message me if you need any more help.

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