pygame collision detection between draw.circle and draw.rect [duplicate] - pygame

This question already has answers here:
How can I know if a circle and a rect is touched in Pygame?
(1 answer)
Issue finding side of collision for Circle-Rectangle collision
(1 answer)
Detect collision between textbox and circle in pygame
(1 answer)
How do I detect collision in pygame?
(5 answers)
Sometimes the ball doesn't bounce off the paddle in pong game
(1 answer)
Closed 2 years ago.
Is there a way to handle collision detection between draw.circle and draw.rect ?
If I try to use sprite collision detection than it says circle has not got rect atrributes.
I create two players: rectangles. I create one ball: circle. I would like to handle the collision between two players and a ball in the best way possible. Could you help ?
I present my code below:
# DATE: 090215
TWO PLAYERS
CONTROL VIA KEYBOARD OR MOUSE
#
import pygame, sys
from pygame.constants import MOUSEMOTION, K_LEFT, K_RIGHT, K_DOWN, K_UP
pygame.init()
clock = pygame.time.Clock()
SCREENW = 800
SCREENH = 600
SCREEN = pygame.display.set_mode((SCREENW,SCREENH),0,32)
WHITE = (255,255,255)
BLACK = (0,0,0)
BLUE = (0,70,160)
RED = (255,0,0)
RECTH = 100
RECTW = 30
#players
PLAYER1P = (0,((SCREENH - RECTH)/2),RECTW,RECTH)
PLAYER2P = ((SCREENW-RECTW),((SCREENH - RECTH)/2),RECTW,RECTH)
# BALLS append with a ball for collision detection purposes
BALLS = []
# PLAYERS append with players for collision detection purposes
PLAYERS = []
# CLASS TO DEFINE PLAYER
class PlayerSprite(pygame.sprite.Sprite):
# define object atributes
def __init__(self,x,y,rwidth,rheight):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.width = rwidth
self.height = rheight
# define object behavior
def update(self,control,Surface,color):
key = pygame.key.get_pressed()
self.control = control
if self.control == 1:
self.y = pygame.mouse.get_pos()[1]
if self.y >= SCREENH - RECTH:
self.y = SCREENH - RECTH
if self.control == 0:
dist = 20
if key[pygame.K_DOWN]:
self.y += dist
if key[pygame.K_UP]:
self.y -= dist
if key[pygame.K_LEFT]:
None
if key[pygame.K_RIGHT]:
None
if self.y >= SCREENH - RECTH:
self.y = SCREENH - RECTH
if self.y <= 0:
self.y = 0
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# draw player as a rectangle
# the important bit is that here you can change player shape
self.player = pygame.Rect(self.x,self.y,self.width,self.height)
pygame.draw.rect(Surface,color,self.player)
class CircleSprite(pygame.sprite.Sprite):
# define object atributes
def __init__(self,x,y,rwidth,rheight,speedx,speedy):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.speedx = speedx
self.speedy = speedy
self.width = rwidth
self.height = rheight
# define object behavior
def update(self,Surface,color):
#self.control = control
#if self.control == 1:
# self.y = pygame.mouse.get_pos()[1]
self.x += self.speedx
self.y += self.speedy
# draw player as a rectangle
# the important bit is that here you can change player shape
pygame.draw.circle(Surface, color, (self.x, self.y), self.width, 0)
# main function
def main():
# CREATE PLAYER OBJECT before WHILE loop
prec1 = PlayerSprite(0,SCREENH/2 - RECTH/2,RECTW,RECTH)
prec2 = PlayerSprite(SCREENW - RECTW,SCREENH/2 - RECTH/2,RECTW,RECTH)
prec3 = CircleSprite(SCREENW/2,SCREENH/2,RECTW/3,RECTH/3,10,5)
PLAYERS.append(prec1)
PLAYERS.append(prec2)
BALLS.append(prec3)
while True:
# update OBJECT position
SCREEN.fill(WHITE)
# 0 = KEYBOARD
# 1 = MOUSE
prec1.update(0,SCREEN,BLUE)
prec2.update(1,SCREEN,BLACK)
prec3.update(SCREEN,RED)
# check collision
is_a_collision = pygame.sprite.collide_mask(prec1,prec3)
if is_a_collision:
print "Boom1"
# change direction
if prec3.x >= SCREENW or prec3.x <= 0:
prec3.speedx = - prec3.speedx
if prec3.y >= SCREENH or prec3.y <= 0:
prec3.speedy = - prec3.speedy
pygame.display.update()
clock.tick(50)
pygame.quit()
main()

Related

How to change a sprites rotation while a button is down [duplicate]

This question already has answers here:
How do I rotate an image around its center using Pygame?
(6 answers)
How to turn the sprite in pygame while moving with the keys
(1 answer)
Closed 11 months ago.
Just started using sprites, figured out how to make it blit, set the image, move with arrow keys, but I don't understand how to rotate it. I've tried some things only nothing seems to work or make sense, Here's my problem.
I want the cube figure to rotate 90 degrees while pressing D or moving right, vise-versa for left. Some things have made sense but I still cannot rotate it. Here's my code, any sort of explanation helps, Thanks.
import pygame_textinput
import prompts
pygame.init()
textinput = pygame_textinput.TextInputVisualizer()
black = ("225, 225, 225")
font = pygame.font.SysFont("Comicsansms", 55)
display = pygame.display.set_mode((575, 375))
pygame.display.set_caption("Game")
clock = pygame.time.Clock()
pygame.key.set_repeat(200, 25)
ISSAC = pygame.image.load("issac.png")
class Issac(pygame.sprite.Sprite):
def __init__(self, image):
self.image = image
self.og_img = self.image
self.x = 0
self.y = 0
self.angle = 0
self.change_angle = 0
self.rect = self.image.get_rect()
def movement(self):
key = pygame.key.get_pressed()
ws = 3
if key[pygame.K_w]:
self.y -= ws
elif key[pygame.K_s]:
self.y += ws
if key[pygame.K_a]:
self.x -= ws
elif key[pygame.K_d]:
self.x += ws
self.change_angle = 90
def draw(self, display):
display.blit(self.image, (self.x, self.y))
def change(self):
if self.angle_change != 0:
self.angle = self.angle_change
issac = Issac(ISSAC)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
issac.movement()
display.fill((255, 255, 255))
issac.draw(display)
pygame.display.update()
clock.tick(60)```

Pygame Error: TypeError: projectile() takes 1 positional argument but 5 were given in Pygame

I am still a newbie to Python and I am following a tutorial on Youtube about Pygame. I came across an error while running Pygame. I tried looking up the solution here but it seems that my error is a bit different. Hoping for some insights from you guys on how to fix this.
# Character Class
class player(object):
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.velocity = 5
self.isJump = False
self.jumpCount = 10
self.left = False
self.right = False
self.walkCount = 0
self.standing = True
def draw(self, window):
# Draw Image
if self.walkCount + 1 >= 27:
self.walkCount = 0
if not (self.standing):
if self.left:
window.blit(walkLeft[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
elif self.right:
window.blit(walkRight[self.walkCount // 3], (self.x, self.y))
self.walkCount += 1
else:
if self.right:
window.blit(walkRight[0], (self.x, self.y))
else:
window.blit(walkLeft[0], (self.x, self.y))
# Projectile Class
def projectile(object):
def __init__(self, x, y, radius, color, facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.velocity = 8 * facing
def draw(self, window):
pygame.draw.circle(window, self.color, (self.x, self.y), self.radius)
# Game Function
def redrawGameWindow():
window.blit(background, (0, 0))
hero.draw(window)
for bullet in bullets:
bullet.draw(window)
pygame.display.update()
# Main Loop
hero = player(300, 410, 64, 64)
bullets = []
run = True
while run:
clock.tick(27)
# Check for events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# Bullets
for bullet in bullets:
if bullet.x < 500 and bullet.x > 0:
bullet.x += bullet.velocity
else:
bullets.pop(bullets.index(bullet))
# Movements
keys = pygame.key.get_pressed()
# Shoot Bullets
if keys[pygame.K_SPACE]:
if hero.left:
facing = -1
else:
facing = 1
if len(bullets) < 5:
bullets.append(projectile(round(hero.x + hero.width //2), round(hero.y + hero.height //2), 6, (0,0,0), facing))
The error that I receive was this:
bullets.append(projectile(round(hero.x + hero.width //2), round(hero.y + hero.height //2), 6, (0,0,0), facing))
TypeError: projectile() takes 1 positional argument but 5 were given
The code is defining a function projectile(), with a local-function __init__() - not a class.
# Projectile Class
def projectile(object): # <-- HERE
def __init__(self, x, y, radius, color, facing):
self.x = x
...
It just needs a minor syntax change:
# Projectile Class
class projectile(object): # <-- HERE
def __init__(self, x, y, radius, color, facing):
self.x = x
...
This probably should be a comment, not an answer, but it took me a few minutes to work it out myself, so I figured maybe it's worth a full answer.

collision detection in snake game

I have tried to make a snake game using python's pygame. What I did was create 2 segments in the start at a particular distance this will be my snake and as it eats more objects it will grow. But I want my game to end when the snakes head collides with any other segment. I used sprite collide method to detect collision between snakes head(here snake_segment[0]) and the segment group.Here's the code which is relevant to my problem
class Segment(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([segment_width,segment_height])
self.image.fill(black)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
# we create the apple object here
class Apple(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.transform.scale(apple1,(25,25))
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = random.randrange(30,screen_width-30)
self.rect.y = random.randrange(30,screen_height-30)
# we create the function for sprites so that we can manage all the sprites
all_sprites = pygame.sprite.Group()
segment_group = pygame.sprite.Group()
snake_segment = [] # we create this list to store all thhe segments
for i in range(0,2):
x = 250 - (segment_width+ segement_margin)*i
y= 30
segments =Segment(x,y)
snake_segment.append(segments)
all_sprites.add(segments)
segment_group.add(segments)
apple_group = pygame.sprite.Group()
apple =Apple()
apple_group.add(apple)
all_sprites.add(apple)
running = True
while running:
# we tweak the fps here
clock.tick(fps)
# we keep track of all the events here
for event in pygame.event.get():
# if the user wishes to quit
if event.type == pygame.QUIT:
running = False
# we set the movement of the segments
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
y_change = (segment_height + segement_margin)*-1
x_change=0
if event.key == pygame.K_DOWN:
y_change = (segment_height + segement_margin)
x_change= 0
if event.key == pygame.K_LEFT:
x_change = (segment_width + segement_margin)*-1
y_change = 0
if event.key == pygame.K_RIGHT:
x_change = (segment_width + segement_margin)
y_change = 0
# we remove the last element of the snake segment
old_segment = snake_segment.pop()
all_sprites.remove(old_segment)
# we add the new element on the top of the snake
x = snake_segment[0].rect.x + x_change
y = snake_segment[0].rect.y + y_change
segment = Segment(x,y)
snake_segment.insert(0,segment)
all_sprites.add(segment)
# here we detect collison between apple group and snake sprite and make changes
eat_coll = pygame.sprite.spritecollide(snake_segment[0],apple_group,True)
if eat_coll:
x = snake_segment[-1].rect.x - x_change
y = snake_segment[-1].rect.y - y_change
segment = Segment(x,y)
snake_segment.insert(-1,segment)
segment_group.add(segment)
apple = Apple()
apple_group.add(apple)
all_sprites.add(apple)
bite_sound.play()
snake_coll = pygame.sprite.spritecollide(snake_segment[0],segment_group,False)
if snake_coll:
running = False
# update each sprite
all_sprites.add(segment)
# here we fill the background
screen.blit(background_image,background_rect)
all_sprites.draw(screen)
# we will update the screen
pygame.display.update()
Just check if the snakes head is inside the snakes body.
def self_collision(self):
"""
Return True if head is inside the body
"""
return self.snake_segnment[0] in self.snake_segment[1:]

Space invaders clone issue

i am working on something like Space Invaders since i just started to learn programing i try to keep it simple, what i want is enemy ships coming from top of the screen and then settling in one line.I managed to make them coming from top at some speed but i dont know how to make them stop at a line,for example at y = 40.The code is below:
# Sprites vjezba.py
import pygame
# Define colors
black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
green = (0,0,255)
# Define screen size
SCREEN_WIDTH = 420
SCREEN_HEIGHT = 400
# Classes
class Square(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(red)
self.rect = self.image.get_rect()
def update(self):
pos = pygame.mouse.get_pos()
self.rect.x = pos[0]
self.rect.y = pos[1]
class Enemies(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20,20])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
speed_y = 1
self.rect.y += speed_y
# Initialize pygame
pygame.init()
# Initialize screen
screen = pygame.display.set_mode([SCREEN_WIDTH,SCREEN_HEIGHT])
# Set the clock
clock = pygame.time.Clock()
# Create sprites lists
square_list = pygame.sprite.Group()
enemies_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
# Create sprites
#--- Enemies sprites
diff_x = 0
diff_y = 0
for i in range(10):
enemies = Enemies()
enemies.rect.x = 20 + diff_x
diff_x += 40
enemies.rect.y = 20 - diff_y
diff_y += 20
enemies_list.add(enemies)
all_sprites_list.add(enemies)
# --- Square sprite
square = Square()
square.rect.x = 200
square.rect.y = 370
square_list.add(square)
all_sprites_list.add(square)
# -------Main Loop----------
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
all_sprites_list.update()
screen.fill(white)
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(40)
pygame.quit()
At the moment, your update() for the Enemies looks like this:
def update(self):
speed_y = 1
self.rect.y += speed_y
This has two obvious flaws:
The speed is set locally, then discarded again at the end of the method; and
It doesn't know anything about position.
To fix this, I suggest making speed_y an instance attribute:
def __init__(self):
...
self.speed_y = 1
Allowing the setting of a target position
def set_target(y_pos):
self.y_target = y_pos
And using this information in update, for example:
def update(self):
self.rect.y += self.speed_y
if self.rect.y >= self.y_target:
self.speed_y = 0
This is a very basic example that just stops at the target y (and only works in one dimension), but hopefully gives you an idea of how to control the movement of your Enemies.

Pygames math.Vector2( ) errors

Im converting my small physics test code in pygame from using pairs of variables to describe position, velocity and acceleration into math.Vector2()'s. The reason being is obvious since there are a whole lot of methods relating to the Vector2 that make it easy to find the length, normalize, cross product so on and so forth.
In the pygame docs it also has a whole bunch of numerical operations it supports like vec*number, vec*=vec etc. However my issue has arisen when I start to use the vec+=vec or vec*=vec. I am getting this kind of error...
"malloc: * error for object 0x7fb4a1ec31a0: pointer being freed was not allocated"
If I comment out all those operations the code runs fine without animation of course. Is there a bug with Vector2() or am I just utilising it wrong?
import pygame, math, random
pygame.init()
class Circle(pygame.sprite.Sprite):
def __init__(self, screen):
pygame.sprite.Sprite.__init__(self)
self.screen = screen
self.position = pygame.math.Vector2(random.randrange(20,self.screen.get_width()), self.screen.get_height()/3)
self.velocity = pygame.math.Vector2(0.0, 0.0)
self.acceleration = pygame.math.Vector2(0.0, 0.1)
self.netForce = pygame.math.Vector2(0.0, 0.0)
self.x = random.randrange(20,self.screen.get_width())
self.y = self.screen.get_height()/2
self.radius = random.randrange(5,30)
self.image = pygame.Surface((self.radius*2,self.radius*2))
self.image.set_colorkey((0,0,0))
self.image.set_alpha(120)
self.mass = self.radius/15.0
pygame.draw.circle(self.image, (175,255,0), (self.radius,self.radius), self.radius)
self.image = self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.center = self.position
def update(self):
self.calcPos()
self.checkBounds()
self.rect.center = self.position
self.netForce *= 0.0
def calcPos(self):
self.acceleration = self.netForce
self.velocity += self.acceleration
self.position += self.velocity
def applyForce(self, force):
force /self.mass
self.netForce += force
def checkBounds(self):
if self.position[1] > self.screen.get_height():
self.acceleration[1] *= -1.0
self.position[1] = self.screen.get_height()
if self.position[0] > self.screen.get_width():
self.acceleration[0] *= -1.0
self.position[0] = self.screen.get_width()
if self.position[1] < 0:
self.acceleration[1] *= -1.0
if self.position[0] < 0:
self.acceleration[0] *= -1.0
def main():
screen = pygame.display.set_mode((600,400))
background = pygame.Surface((screen.get_size()))
background.fill((150,150,150))
background = background.convert()
circleGRP = pygame.sprite.Group() #Add balls
for x in range(10):
circleGRP.add(Circle(screen))
wind = pygame.math.Vector2(1.0, 0)
gravity = pygame.math.Vector2(0, 1.0)
clock = pygame.time.Clock()
mainLoop = True
while mainLoop:
clock.tick(30) #Clock
for event in pygame.event.get(): #Key events
if event.type == pygame.QUIT:
mainLoop = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
mainLoop = False
elif event.type == pygame.MOUSEBUTTONDOWN: #Add wind
if pygame.mouse.get_pressed()[0]:
for circle in circleGRP:
circle.applyForce(wind)
#----------------------------------------------------------------------------
for circle in circleGRP: #Add gravity
gravity = gravity * circle.mass
circle.applyForce(gravity)
#pass
#circleX = circle.dx * -1 #Add drag
#circleY = circle.dy * -1
#drag = (circleX/80* circle.mass* (circle.radius/5), circleY/80* circle.mass* (circle.radius/5))
#circle.applyForce(drag)
#----------------------------------------------------------------------------
circleGRP.update()
screen.blit(background, (0,0))
circleGRP.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
Alternatively, you can use the Vec2d class that is given here.
It has operator overloading (can use with tuples or lists), uses slots for perforance, is picklable, implements list interface (so it's compatible with pygame functions), has a fair bit of high level vector operators (for performance and readability) and has unit tests built in.
I have worked with it in simulations and physics testings, and it provides all that you need.