How to make my rectangle rotate with a rotating sprite - python

So I been having this problem with my rectangle/projectile rotation, I want it so that my rectangle/projectile will rotate with my rotating sprite but the code I'm trying for it is not working for me, The code that I'm trying is giving me this error. 'pygame.Surface' object has no attribute 'x' I have tried moving the code around, I have also tried to change the code so I wont get the error no more, and I have tried using a hitbox but I still keep getting the error. This is my two sprites
The code I'm trying
self.dist = 100
dx = self.pin.x + self.dist*math.cos(-self.pin.angle*(math.pi/180)) -65 # why offset needed ?
dy = self.pin.y + self.dist*math.sin(-self.pin.angle*(math.pi/180)) -50 # why offset needed ?
self.rect.topleft = (dx,dy)
pygame.draw.rect(window,self.color,self.rect)
My full code
import pygame,math,random
pygame.init()
# Windowing screen width and height
width = 500
height = 500
window = pygame.display.set_mode((width,height))
# Name of window
pygame.display.set_caption("Game")
# The Background
background = pygame.image.load("img/BG.png")
def blitRotate(surf, image, pos, originPos, angle):
# calcaulate the axis aligned bounding box of the rotated image
w, h = image.get_size()
sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
pivot_rotate = pivot.rotate(angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
# get a rotated image
rotated_image = pygame.transform.rotate(image, angle)
# rotate and blit the image
surf.blit(rotated_image, origin)
# Player class
class Player:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.speed = 4
self.cannon = pygame.image.load("img/Cannon.png")
self.cannon = pygame.transform.scale(self.cannon,(self.cannon.get_width()//2, self.cannon.get_height()//2))
self.rect = pygame.Rect(x,y,width,height)
self.hitbox = (self.x,self.y,30,30)
self.image = self.cannon
self.rect = self.image.get_rect(center = (self.x, self.y))
self.look_at_pos = (self.x, self.y)
self.isLookingAtPlayer = False
self.look_at_pos = (x,y)
self.angle = 0
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.hitbox)
player_rect = self.cannon.get_rect(center = self.get_rect().center)
player_rect.centerx -= 0
player_rect.centery += 90
# Another part of cannon rotating
dx = self.look_at_pos[0] - self.rect.centerx
dy = self.look_at_pos[1] - self.rect.centery
angle = (180/math.pi) * math.atan2(-dy, dx) - 90
gun_size = self.image.get_size()
pivot_abs = player_rect.centerx, player_rect.top + 13
pivot_rel = (gun_size[0] // 2, 105)
pygame.draw.rect(window,self.color,self.rect)
blitRotate(window, self.image,pivot_abs, pivot_rel, angle)
def lookAt( self, coordinate ):
self.look_at_pos = coordinate
# Players gun
class projectile(object):
def __init__(self,x,y,dirx,diry,color):
self.x = x
self.y = y
self.dirx = dirx
self.diry = diry
self.pin = pygame.image.load("img/Pin.png")
self.pin = pygame.transform.scale(self.pin,(self.pin.get_width()//6, self.pin.get_height()//6))
self.rect = self.pin.get_rect()
self.topleft = ( self.x, self.y )
self.speed = 10
self.color = color
self.hitbox = (self.x + 20, self.y, 30,40)
def move(self):
self.x += self.dirx * self.speed
self.y += self.diry * self.speed
def draw(self):
self.rect.topleft = (round(self.x), round(self.y))
window.blit(self.pin,self.rect)
self.hitbox = (self.x + 20, self.y,30,30)
# For rotating the the projectile
self.dist = 100
dx = self.pin.x + self.dist*math.cos(-self.pin.angle*(math.pi/180)) -65 # why offset needed ?
dy = self.pin.y + self.dist*math.sin(-self.pin.angle*(math.pi/180)) -50 # why offset needed ?
self.rect.topleft = (dx,dy)
pygame.draw.rect(window,self.color,self.rect)
# The color white
white = (255,255,255)
# The xy cords, width, height and color of my classes[]
playerman = Player(350,385,34,75,white)
# This is where my balloons get hit by the bullet and disappers
# redrawing window
def redrawwindow():
window.fill((0,0,0))
# Drawing the window in
window.blit(background,(0,0))
# drawing the player in window
playerman.draw()
# Drawing the players bullet
for bullet in bullets:
bullet.draw()
# Frames for game
fps = 30
clock = pygame.time.Clock()
#projectile empty list
bullets = []
# main loop
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if len(bullets) < 6700:
mousex , mousey = pygame.mouse.get_pos()
start_x , start_y = playerman.rect.x + 12, playerman.rect.y - 3
mouse_x , mouse_y = event.pos
dir_x , dir_y = mouse_x - start_x , mouse_y - start_y
distance = math.sqrt(dir_x**2 + dir_y**2)
if distance > 0:
new_bullet = projectile(start_x, start_y, dir_x/distance , dir_y/distance, (0,0,0))
bullets.append(new_bullet)
for bullet in bullets[:]:
bullet.move()
if bullet.x < 0 or bullet.x > 900 or bullet.y < 0 or bullet.y > 900:
bullets.pop(bullets.index(bullet))
# gun rotation
mousex, mousey = pygame.mouse.get_pos()
if not playerman.isLookingAtPlayer:
playerman.lookAt((mousex, mousey))
# telling game that key means when a key get pressed
keys = pygame.key.get_pressed()
# The player moving when the key a is pressed
if keys[pygame.K_a] and playerman.x > playerman.speed:
playerman.x -= playerman.speed
# The player moving when the key d is pressed
if keys[pygame.K_d] and playerman.x < 500 - playerman.width - playerman.speed:
playerman.x += playerman.speed
# Calling the redraw function
redrawwindow()
# updating game
pygame.display.update()
# quiting the game
pygame.quit()

You are already moving the pin in the projectile.move method. In the projectile.draw method you just have to rotate the pin. See How do I rotate an image around its center using PyGame? and How to rotate an image(player) to the mouse direction?:
class projectile(object):
# [...]
def draw(self):
self.rect.center = (round(self.x), round(self.y))
angle = math.degrees(math.atan2(-self.diry, self.dirx)) - 90
rotated_pin = pygame.transform.rotate(self.pin, angle)
rotated_rect = rotated_pin.get_rect(center = self.rect.center)
pygame.draw.rect(window,self.color, rotated_rect)
window.blit(rotated_pin, rotated_rect)
self.hitbox = (self.x + 20, self.y,30,30)
You have to find a starting position of the pin. The pin should start somewhere on top of the blowpipe. Add a get_pivot method to the Player class:
class Player:
# [...]
def get_pivot(self):
player_rect = self.cannon.get_rect(center = self.get_rect().center)
return player_rect.centerx, player_rect.top + 103
Add a get_angle method that calculates the angle of the blowpipe:
class Player:
# [...]
def get_angle(self):
pivot_abs = self.get_pivot()
dx = self.look_at_pos[0] - pivot_abs[0]
dy = self.look_at_pos[1] - pivot_abs[1]
return math.degrees(math.atan2(-dy, dx))
Use this methods to compute the top of the blow pipes:
class Player:
# [...]
def get_top(self):
pivot_x, pivot_y = self.get_pivot()
angle = self.get_angle()
length = 100
top_x = pivot_x + length * math.cos(math.radians(angle))
top_y = pivot_y - length * math.sin(math.radians(angle))
return top_x, top_y
You can also use the get_pivot and get_angle methods in the draw method:
class Player:
# [...]
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.hitbox)
gun_size = self.image.get_size()
pivot_abs = self.get_pivot()
pivot_rel = (gun_size[0] // 2, 105)
angle = self.get_angle() - 90
pygame.draw.rect(window,self.color,self.rect)
blitRotate(window, self.image,pivot_abs, pivot_rel, angle)
Use get_top to set the starting position of the pin:
mousex, mousey = pygame.mouse.get_pos()
start_x, start_y = playerman.get_top()
mouse_x, mouse_y = event.pos
dir_x, dir_y = mouse_x - start_x , mouse_y - start_y
distance = math.sqrt(dir_x**2 + dir_y**2)
if distance > 0:
new_bullet = projectile(start_x, start_y, dir_x/distance, dir_y/distance, (0,0,0))
bullets.append(new_bullet)
Draw the pins in before the blowpipe so it looks like the pins are coming out of the blowpipe:
def redrawwindow():
window.fill((0,0,0))
# Drawing the window in
window.blit(background,(0,0))
# Drawing the players bullet
for bullet in bullets:
bullet.draw()
# drawing the player in window
playerman.draw()
Complete examplee:
import pygame,math,random
pygame.init()
# Windowing screen width and height
width = 500
height = 500
window = pygame.display.set_mode((width,height))
# Name of window
pygame.display.set_caption("Game")
# The Background
background = pygame.image.load("img/BG.png")
def blitRotate(surf, image, pos, originPos, angle):
# calcaulate the axis aligned bounding box of the rotated image
w, h = image.get_size()
sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
pivot_rotate = pivot.rotate(angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
# get a rotated image
rotated_image = pygame.transform.rotate(image, angle)
# rotate and blit the image
surf.blit(rotated_image, origin)
# Player class
class Player:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.speed = 4
self.cannon = pygame.image.load("img/Cannon.png")
self.cannon = pygame.transform.scale(self.cannon,(self.cannon.get_width()//2, self.cannon.get_height()//2))
self.rect = pygame.Rect(x,y,width,height)
self.hitbox = (self.x,self.y,30,30)
self.image = self.cannon
self.rect = self.image.get_rect(center = (self.x, self.y))
self.look_at_pos = (self.x, self.y)
self.isLookingAtPlayer = False
self.look_at_pos = (x,y)
self.angle = 0
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def get_pivot(self):
player_rect = self.cannon.get_rect(center = self.get_rect().center)
return player_rect.centerx, player_rect.top + 103
def get_angle(self):
pivot_abs = self.get_pivot()
dx = self.look_at_pos[0] - pivot_abs[0]
dy = self.look_at_pos[1] - pivot_abs[1]
return math.degrees(math.atan2(-dy, dx))
def get_top(self):
pivot_x, pivot_y = self.get_pivot()
angle = self.get_angle()
length = 100
top_x = pivot_x + length * math.cos(math.radians(angle))
top_y = pivot_y - length * math.sin(math.radians(angle))
return top_x, top_y
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.hitbox)
gun_size = self.image.get_size()
pivot_abs = self.get_pivot()
pivot_rel = (gun_size[0] // 2, 105)
angle = self.get_angle() - 90
pygame.draw.rect(window,self.color,self.rect)
blitRotate(window, self.image,pivot_abs, pivot_rel, angle)
def lookAt( self, coordinate ):
self.look_at_pos = coordinate
# Players gun
class projectile(object):
def __init__(self,x,y,dirx,diry,color):
self.x = x
self.y = y
self.dirx = dirx
self.diry = diry
self.pin = pygame.image.load("img/Pin.png")
self.pin = pygame.transform.scale(self.pin,(self.pin.get_width()//6, self.pin.get_height()//6))
self.rect = self.pin.get_rect()
self.center = ( self.x, self.y )
self.speed = 10
self.color = color
self.hitbox = (self.x + 20, self.y, 30,40)
def move(self):
self.x += self.dirx * self.speed
self.y += self.diry * self.speed
def draw(self):
self.rect.center = (round(self.x), round(self.y))
angle = math.degrees(math.atan2(-self.diry, self.dirx)) - 90
rotated_pin = pygame.transform.rotate(self.pin, angle)
rotated_rect = rotated_pin.get_rect(center = self.rect.center)
pygame.draw.rect(window,self.color, rotated_rect)
window.blit(rotated_pin, rotated_rect)
self.hitbox = (self.x + 20, self.y,30,30)
# The color white
white = (255,255,255)
# The xy cords, width, height and color of my classes[]
playerman = Player(350,385,34,75,white)
# This is where my balloons get hit by the bullet and disappers
# redrawing window
def redrawwindow():
window.fill((0,0,0))
# Drawing the window in
window.blit(background,(0,0))
# Drawing the players bullet
for bullet in bullets:
bullet.draw()
# drawing the player in window
playerman.draw()
# Frames for game
fps = 30
clock = pygame.time.Clock()
#projectile empty list
bullets = []
# main loop
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if len(bullets) < 6700:
mousex, mousey = pygame.mouse.get_pos()
start_x, start_y = playerman.get_top()
mouse_x, mouse_y = event.pos
dir_x, dir_y = mouse_x - start_x , mouse_y - start_y
distance = math.sqrt(dir_x**2 + dir_y**2)
if distance > 0:
new_bullet = projectile(start_x, start_y, dir_x/distance, dir_y/distance, (0,0,0))
bullets.append(new_bullet)
for bullet in bullets[:]:
bullet.move()
if bullet.x < 0 or bullet.x > 900 or bullet.y < 0 or bullet.y > 900:
bullets.pop(bullets.index(bullet))
# gun rotation
mousex, mousey = pygame.mouse.get_pos()
if not playerman.isLookingAtPlayer:
playerman.lookAt((mousex, mousey))
# telling game that key means when a key get pressed
keys = pygame.key.get_pressed()
# The player moving when the key a is pressed
if keys[pygame.K_a] and playerman.x > playerman.speed:
playerman.x -= playerman.speed
# The player moving when the key d is pressed
if keys[pygame.K_d] and playerman.x < 500 - playerman.width - playerman.speed:
playerman.x += playerman.speed
# Calling the redraw function
redrawwindow()
# updating game
pygame.display.update()
# quiting the game
pygame.quit()

Related

How do i make my sprite shoot from the middle of the rectangle?

import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (15,15))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
self.fired = False
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midright[0]
y_dist = -(pos[1] - self.rect.midtop[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right, self.rect.top, self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle) #angle to radians
self.speed = 10 # Speed !!!
self.dx = math.cos(self.angle) * self.speed #caculate speed of x
self.dy = -(math.sin(self.angle) * self.speed) # caculate speed of y
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > WINDOW_WIDTH or self.rect.bottom < 0 or self.rect.top > WINDOW_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (15,15))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midleft[0]
y_dist = -(pos[1] - self.rect.midleft[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle)
self.speed = 10
self.dx = math.cos(self.angle) * self.speed
self.dy = -(math.sin(self.angle) * self.speed)
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
import pygame
import math
#initialise pygame
pygame.init()
#game window
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 750
#create game window
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('Castle Defender')
clock = pygame.time.Clock()
FPS = 60
#load images
background_img = pygame.image.load('Animations/BG.png').convert_alpha()
background = pygame.transform.scale(background_img,(1200,750))
castle_img = pygame.image.load('Animations/Castle.png').convert_alpha()
bullet_img = pygame.image.load('Animations/SmallBullet.png').convert_alpha()
b_w = bullet_img.get_width()
b_h = bullet_img.get_height()
bullet_img = pygame.transform.scale(bullet_img, (int(b_w * 0.075), int(b_h * 0.075)))
WHITE =(255,255,255)
#Castle class
class Castle():
def __init__(self, image, x, y, scale):
self.health = 1000
self.max_health = self.health
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def shoot(self):
pos = pygame.mouse.get_pos()
x_dist = pos[0] - self.rect.midleft[0]
y_dist = -(pos[1] - self.rect.midleft[1])
self.angle = math.degrees(math.atan2(y_dist, x_dist))
#mouseclick
if pygame.mouse.get_pressed()[0] and self.fired == False:
self.fired = True
bullet = Bullet(bullet_img, self.rect.right[0], self.rect.right[1], self.angle)
bullet_group.add(bullet)
#reset mouseclick
if pygame.mouse.get_pressed()[0] == False:
self.fired = False
#Method
def draw(self):
self.image = self.image
win.blit(self.image, self.rect)
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.angle = math.radians(angle)
self.speed = 10
self.dx = math.cos(self.angle) * self.speed
self.dy = -(math.sin(self.angle) * self.speed)
def update(self):
#check if bullet has gone off the screen
if self.rect.right < 0 or self.rect.left > SCREEN_WIDTH or self.rect.bottom < 0 or self.rect.top > SCREEN_HEIGHT:
self.kill()
#move bullet
self.rect.x += self.dx
self.rect.y += self.dy
castle = Castle(castle_img, WINDOW_WIDTH - 1350, WINDOW_HEIGHT - 400, 0.7)
bullet_group = pygame.sprite.Group()
run = True
while run:
clock.tick(FPS)
win.blit(background, (0, 0))
castle.draw()
castle.shoot()
#bullet drawing
bullet_group.update()
bullet_group.draw(win)
print(len(bullet_group))
#event handler
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
#update display window
pygame.display.update()
pygame.quit()
So my code works without producing an error but when i shoot my bullet it comes out of the topright of the rectangle for my castle whereas i want it to be near the middle as for my image it is just shooting from the middle of nowhere as my image is not a square.
The starting position of the bullet should be the center of the rectangle:
bullet = Bullet(bullet_img, self.rect.right, self.rect.top, self.angle)
bullet = Bullet(bullet_img, self.rect.centerx, self.rect.centery, self.angle)
Set the center position of the bullet rectangle instead of the top left position:
class Bullet(pygame.sprite.Sprite):
def __init__(self, image, x, y, angle):
pygame.sprite.Sprite.__init__(self)
self.image = image
self.rect = self.image.get_rect()
self.rect.centerx = x # <---
self.rect.centery = y # <---

Sprite rotation facing mouse stops working when map scrolls

I have implemented a rotation for the player sprite so it faces the mouse, but when I move outside of the original window and the 'camera' starts moving, the rotation stops working.
Here is my code for player rotation:
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((TILESIZE, TILESIZE))
self.image.fill(WHITE)
self.orig_img = self.image
self.rect = self.image.get_rect(center=(x, y))
self.vel = vec(0, 0)
self.pos = vec(x, y) * TILESIZE
self.last_shot = 0
self.health = 100
def update(self):
self.rotate()
self.get_keys()
self.pos += self.vel * dt
self.rect.center = self.pos
def rotate(self):
_, self.angle = (pg.mouse.get_pos() - self.pos).as_polar()
self.image = pg.transform.rotozoom(self.orig_img, self.angle, 1)
self.rect = self.image.get_rect(center=self.rect.center)
def get_keys(self):
self.vel = vec(0, 0)
keys = pg.key.get_pressed()
if keys[pg.K_LEFT] or keys[pg.K_a]:
self.vel.x = -PLAYERSPEED
if keys[pg.K_RIGHT] or keys[pg.K_d]:
self.vel.x = PLAYERSPEED
if keys[pg.K_UP] or keys[pg.K_w]:
self.vel.y = -PLAYERSPEED
if keys[pg.K_DOWN] or keys[pg.K_s]:
self.vel.y = PLAYERSPEED
if self.vel.x != 0 and self.vel.y != 0:
self.vel *= 0.7071
if keys[pg.K_SPACE]:
now = pg.time.get_ticks()
if now - self.last_shot > BULLET_RATE:
self.last_shot = now
self.shoot()
def shoot(self):
dir = vec(1, 0).rotate(self.angle)
bullet = Bullet(self.pos, dir)
all_sprites.add(bullet)
bullets.add(bullet)
And here for camera and implementing camera in my game loop:
class Camera:
def __init__(self, width, height):
self.camera = pg.Rect(0, 0, width, height)
self.width = width
self.height = height
def apply(self, entity):
return entity.rect.move(self.camera.topleft)
def update(self, target):
x = -target.rect.x + int(WIDTH / 2)
y = -target.rect.y + int(HEIGHT / 2)
# limit scrolling to map size
x = min(0, x) # left
y = min(0, y) # top
x = max(-(self.width - WIDTH), x) # right
y = max(-(self.height - HEIGHT), y) # bottom
self.camera = pg.Rect(x, y, self.width, self.height)
Inside game loop:
for sprite in all_sprites:
screen.blit(sprite.image, camera.apply(sprite))
all_sprites.update()
camera.update(player)
I have read from other posts about making the mouse pos from screen cords to world cords, but I can't figure out how I would do that in my case...
The angle of the image is calculated with the following line of code:
_, self.angle = (pg.mouse.get_pos() - self.pos).as_polar()
pg.mouse.get_pos() is a screen coordinate. So the code will only work if self.pos is also a screen coordinate.
If self.pos is a coordinate in the world, you need to calculate the position relative to the screen.
Pseudo code:
screen_pos = self.pos - camera.camera.topleft
_, self.angle = (pg.mouse.get_pos() - screen_pos).as_polar()

How to make randomly generated balloons that show up every time you shoot a bullet?

I'm trying to make it so that my game will randomly generated balloons at the top and push every other balloon down to make space for the new balloons when I shoot a bullet. I have 6 balloon classes and was trying to make them get randomly generated, but the codes I have tried to make for it is ending up in failures.
At first I tried to tell it when my bullet disappears then just print something but the problem is that the code I used would instantly make it disappear. I also tried drawing new balloons when the bullet collides with balloon's, but I'm I'm not sure where to place the balloons and how to move them.
This is what I tried
for bullet in bullets:
if bullets.pop(bullets.index(bullet)):
print("collide")
My full code
import pygame,math,random
pygame.init()
# Windowing screen width and height
width = 500
height = 500
window = pygame.display.set_mode((width,height))
# Name of window
pygame.display.set_caption("Game")
# The Background
background = pygame.image.load("img/BG.png")
def blitRotate(surf, image, pos, originPos, angle):
# calcaulate the axis aligned bounding box of the rotated image
w, h = image.get_size()
sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
pivot_rotate = pivot.rotate(angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
# get a rotated image
rotated_image = pygame.transform.rotate(image, angle)
# rotate and blit the image
surf.blit(rotated_image, origin)
# Player class
class Player:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.speed = 4
self.cannon = pygame.image.load("img/Cannon.png")
self.cannon = pygame.transform.scale(self.cannon,(self.cannon.get_width()//2, self.cannon.get_height()//2))
self.rect = pygame.Rect(x,y,width,height)
self.hitbox = (self.x,self.y,30,30)
self.image = self.cannon
self.rect = self.image.get_rect(center = (self.x, self.y))
self.look_at_pos = (self.x, self.y)
self.isLookingAtPlayer = False
self.look_at_pos = (x,y)
self.angle = 0
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def get_pivot(self):
player_rect = self.cannon.get_rect(center = self.get_rect().center)
return player_rect.centerx, player_rect.top + 103
def get_angle(self):
pivot_abs = self.get_pivot()
dx = self.look_at_pos[0] - pivot_abs[0]
dy = self.look_at_pos[1] - pivot_abs[1]
return math.degrees(math.atan2(-dy, dx))
def get_top(self):
pivot_x, pivot_y = self.get_pivot()
angle = self.get_angle()
length = 100
top_x = pivot_x + length * math.cos(math.radians(angle))
top_y = pivot_y - length * math.sin(math.radians(angle))
return top_x, top_y
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.hitbox)
gun_size = self.image.get_size()
pivot_abs = self.get_pivot()
pivot_rel = (gun_size[0] // 2, 105)
angle = self.get_angle() - 90
pygame.draw.rect(window,self.color,self.rect)
blitRotate(window, self.image,pivot_abs, pivot_rel, angle)
def lookAt( self, coordinate ):
self.look_at_pos = coordinate
# Players gun
class projectile(object):
def __init__(self,x,y,dirx,diry,color):
self.x = x
self.y = y
self.dirx = dirx
self.diry = diry
self.pin = pygame.image.load("img/Pin.png")
self.pin = pygame.transform.scale(self.pin,(self.pin.get_width()//6, self.pin.get_height()//6))
self.rect = self.pin.get_rect()
self.center = ( self.x, self.y )
self.speed = 10
self.color = color
self.hitbox = (self.x + 20, self.y, 30,40)
def move(self):
self.x += self.dirx * self.speed
self.y += self.diry * self.speed
def draw(self):
self.rect.center = (round(self.x), round(self.y))
angle = math.degrees(math.atan2(-self.diry, self.dirx)) - 90
rotated_pin = pygame.transform.rotate(self.pin, angle)
rotated_rect = rotated_pin.get_rect(center = self.rect.center)
window.blit(rotated_pin, rotated_rect)
self.hitbox = (self.x + 20, self.y,30,30)
# Green balloon
class Gballoon:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.balloon = [pygame.image.load("img/Green_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Green_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "greenpop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "greenpop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
green_image = image_list[self.anim_index]
green_rect = green_image.get_rect(center = self.get_rect().center)
green_rect.centerx
green_rect.centery += 5
window.blit(green_image,green_rect)
class Bballoon:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.balloon = [pygame.image.load("img/Blue_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Blue_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "greenpop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "greenpop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
green_image = image_list[self.anim_index]
green_rect = green_image.get_rect(center = self.get_rect().center)
green_rect.centerx
green_rect.centery += 5
window.blit(green_image,green_rect)
class Oballoon:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.balloon = [pygame.image.load("img/Orange_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Orange_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "greenpop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "greenpop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
green_image = image_list[self.anim_index]
green_rect = green_image.get_rect(center = self.get_rect().center)
green_rect.centerx
green_rect.centery += 5
window.blit(green_image,green_rect)
class Pballoon:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.balloon = [pygame.image.load("img/Pink_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Pink_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "greenpop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "greenpop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
green_image = image_list[self.anim_index]
green_rect = green_image.get_rect(center = self.get_rect().center)
green_rect.centerx
green_rect.centery += 5
window.blit(green_image,green_rect)
class Pballoon:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.balloon = [pygame.image.load("img/Purple_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Purple_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "greenpop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "greenpop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
green_image = image_list[self.anim_index]
green_rect = green_image.get_rect(center = self.get_rect().center)
green_rect.centerx
green_rect.centery += 5
window.blit(green_image,green_rect)
class Rballoon:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.balloon = [pygame.image.load("img/Red_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Red_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "greenpop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "greenpop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
green_image = image_list[self.anim_index]
green_rect = green_image.get_rect(center = self.get_rect().center)
green_rect.centerx
green_rect.centery += 5
window.blit(green_image,green_rect)
# The color white
white = (255,255,255)
# The xy cords, width, height and color of my classes[]
playerman = Player(350,385,34,75,white)
green1 = Gballoon(180,200,110,40,white)
blue1 = Bballoon(330,250,110,40,white)
orange1 = Oballoon(100,200,110,40,white)
pink1 = Oballoon(300,250,110,40,white)
purple1 = Pballoon(400,250,110,40,white)
red1 = Rballoon(300,200,110,40,white)
# A list for my classess
greens = [green1]
blues = [blue1]
oranges = [orange1]
pinks = [pink1]
purples = [purple1]
reds = [red1]
# This is where my balloons get hit by the bullet and disappers
# redrawing window
def redrawwindow():
window.fill((0,0,0))
# Drawing the window in
window.blit(background,(0,0))
# drawing the player in window
playerman.draw()
# Drawing all my ballons in window
for Gballoon in greens:
Gballoon.draw()
for Bballoon in blues:
Bballoon.draw()
for Oballoon in oranges:
Oballoon.draw()
for Pballoon in purples:
Pballoon.draw()
for Rballoon in reds:
Rballoon.draw()
# Drawing the players bullet
for bullet in bullets:
bullet.draw()
# Frames for game
fps = 30
clock = pygame.time.Clock()
#projectile empty list
bullets = []
# main loop
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if len(bullets) < 6700:
mousex, mousey = pygame.mouse.get_pos()
start_x, start_y = playerman.get_top()
mouse_x, mouse_y = event.pos
dir_x, dir_y = mouse_x - start_x , mouse_y - start_y
distance = math.sqrt(dir_x**2 + dir_y**2)
if distance > 0:
new_bullet = projectile(start_x, start_y, dir_x/distance, dir_y/distance, (0,0,0))
bullets.append(new_bullet)
for bullet in bullets[:]:
bullet.move()
if bullet.x < 0 or bullet.x > 900 or bullet.y < 0 or bullet.y > 900:
bullets.pop(bullets.index(bullet))
# Making game detect when to del the ballon
for bullet in bullets:
for Gballoon in greens:
if bullet.rect.colliderect(Gballoon.hitbox):
Gballoon.direction = "greenpop"
bullets.pop(bullets.index(bullet))
for Gballoon in greens:
for one in range(len(greens)-1,-1,-1):
if greens[one].anim_index == 5:
del greens[one]
for i in range(len(greens)):
for j in range(i+1, len(greens)):
if greens[i].rect.colliderect(greens[j]):
greens[i].direction = "greenpop"
greens[j].direction = "greenpop"
for bullet in bullets:
if bullets.pop(bullets.index(bullet)):
print("collide")
# gun rotation
mousex, mousey = pygame.mouse.get_pos()
if not playerman.isLookingAtPlayer:
playerman.lookAt((mousex, mousey))
# telling game that key means when a key get pressed
keys = pygame.key.get_pressed()
# The player moving when the key a is pressed
if keys[pygame.K_a] and playerman.x > playerman.speed:
playerman.x -= playerman.speed
# The player moving when the key d is pressed
if keys[pygame.K_d] and playerman.x < 500 - playerman.width - playerman.speed:
playerman.x += playerman.speed
# Calling the redraw function
redrawwindow()
# updating game
pygame.display.update()
# quiting the game
pygame.quit()
So, your code had a few issue, the main one was where you did
for Gballoon in greens:
Gballoon.draw()
because this overrides the class Gballoon, you cannot use it as a type anymore afterwards. Are you used to code in C#? It looks as a foreach C# loop ;)
Also, you had a lot of redundant code, I modified it to reduce the number of lines, although it is still improvable, it is now much shorter and easier to read.
The code below does what I think you want: each time a bullet touches a balloon, this balloon pops, a new balloon is created randomly (both position and color) and all balloons move down a bit.
import pygame,math,random
pygame.init()
# some variables for display purposes
BALLOON_W, BALLOON_H = 110, 40
X_MIN, X_MAX, Y_MIN, Y_MAX = 0, 500, 0, 30
BALLOONS_Y_INCREMENT = 20
N_NEW_BALLOONS = 3
# Windowing screen width and height
width = 500
height = 500
window = pygame.display.set_mode((width,height))
# Name of window
pygame.display.set_caption("Game")
# The Background
background = pygame.image.load("img/BG.png")
def blitRotate(surf, image, pos, originPos, angle):
# calculate the axis aligned bounding box of the rotated image
w, h = image.get_size()
sin_a, cos_a = math.sin(math.radians(angle)), math.cos(math.radians(angle))
min_x, min_y = min([0, sin_a*h, cos_a*w, sin_a*h + cos_a*w]), max([0, sin_a*w, -cos_a*h, sin_a*w - cos_a*h])
# calculate the translation of the pivot
pivot = pygame.math.Vector2(originPos[0], -originPos[1])
pivot_rotate = pivot.rotate(angle)
pivot_move = pivot_rotate - pivot
# calculate the upper left origin of the rotated image
origin = (pos[0] - originPos[0] + min_x - pivot_move[0], pos[1] - originPos[1] - min_y + pivot_move[1])
# get a rotated image
rotated_image = pygame.transform.rotate(image, angle)
# rotate and blit the image
surf.blit(rotated_image, origin)
# Player class
class Player:
def __init__(self,x,y,width,height,color):
self.x = x
self.y = y
self.width = width
self.height = height
self.color = color
self.speed = 4
self.cannon = pygame.image.load("img/Cannon.png")
self.cannon = pygame.transform.scale(self.cannon,(self.cannon.get_width()//2, self.cannon.get_height()//2))
self.rect = pygame.Rect(x,y,width,height)
self.hitbox = (self.x,self.y,30,30)
self.image = self.cannon
self.rect = self.image.get_rect(center = (self.x, self.y))
self.look_at_pos = (self.x, self.y)
self.isLookingAtPlayer = False
self.look_at_pos = (x,y)
self.angle = 0
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def get_pivot(self):
player_rect = self.cannon.get_rect(center = self.get_rect().center)
return player_rect.centerx, player_rect.top + 103
def get_angle(self):
pivot_abs = self.get_pivot()
dx = self.look_at_pos[0] - pivot_abs[0]
dy = self.look_at_pos[1] - pivot_abs[1]
return math.degrees(math.atan2(-dy, dx))
def get_top(self):
pivot_x, pivot_y = self.get_pivot()
angle = self.get_angle()
length = 100
top_x = pivot_x + length * math.cos(math.radians(angle))
top_y = pivot_y - length * math.sin(math.radians(angle))
return top_x, top_y
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.hitbox)
gun_size = self.image.get_size()
pivot_abs = self.get_pivot()
pivot_rel = (gun_size[0] // 2, 105)
angle = self.get_angle() - 90
pygame.draw.rect(window,self.color,self.rect)
blitRotate(window, self.image,pivot_abs, pivot_rel, angle)
def lookAt( self, coordinate ):
self.look_at_pos = coordinate
# Players gun
class projectile(object):
def __init__(self,x,y,dirx,diry,color):
self.x = x
self.y = y
self.dirx = dirx
self.diry = diry
self.pin = pygame.image.load("img/Pin.png")
self.pin = pygame.transform.scale(self.pin,(self.pin.get_width()//6, self.pin.get_height()//6))
self.rect = self.pin.get_rect()
self.center = ( self.x, self.y )
self.speed = 10
self.color = color
self.hitbox = (self.x + 20, self.y, 30,40)
def move(self):
self.x += self.dirx * self.speed
self.y += self.diry * self.speed
def draw(self):
self.rect.center = (round(self.x), round(self.y))
angle = math.degrees(math.atan2(-self.diry, self.dirx)) - 90
rotated_pin = pygame.transform.rotate(self.pin, angle)
rotated_rect = rotated_pin.get_rect(center = self.rect.center)
window.blit(rotated_pin, rotated_rect)
self.hitbox = (self.x + 20, self.y,30,30)
# balloon
class Balloon:
def __init__(self,x,y,width,height,color, balloon_type):
self.x = x
self.y = y
self.width = width
self.height = height
if(balloon_type.lower() == "green"):
self.balloon = [pygame.image.load("img/Green_Balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Green_Balloon" + str(i) + ".png") for i in range(1,7)]
elif(balloon_type.lower() == "red"):
self.balloon = [pygame.image.load("img/Red_Balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Red_Balloon" + str(i) + ".png") for i in range(1,7)]
elif(balloon_type.lower() == "blue"):
self.balloon = [pygame.image.load("img/Blue_Balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Blue_Balloon" + str(i) + ".png") for i in range(1,7)]
elif(balloon_type.lower() == "pink"):
self.balloon = [pygame.image.load("img/Pink_Balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Pink_Balloon" + str(i) + ".png") for i in range(1,7)]
elif(balloon_type.lower() == "orange"):
self.balloon = [pygame.image.load("img/Orange_Balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Orange_Balloon" + str(i) + ".png") for i in range(1,7)]
elif(balloon_type.lower() == "purple"):
self.balloon = [pygame.image.load("img/Purple_balloon" + str(i) + ".png") for i in range(1,2)]
self.balloon2 = [pygame.image.load("img/Purple_balloon" + str(i) + ".png") for i in range(1,7)]
self.color = color
self.speed = 2
self.rect = pygame.Rect(x,y,width,height)
self.fps = 10
self.clock = pygame.time.Clock()
self.next_frame_time = 0
self.anim_index = 0
self.hitbox = (self.x - 50, self.y - 18, 40, 40)
self.balloon = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon]
self.balloon2 = [pygame.transform.scale(image,(image.get_width()//6, image.get_height()//6))for image in self.balloon2]
self.direction = "pop"
self.direction = "balloon"
def get_rect(self):
self.rect.topleft = (self.x,self.y)
return self.rect
def draw(self):
self.rect.topleft = (self.x,self.y)
pygame.draw.rect(window,self.color,self.rect,2)
pygame.draw.rect(window,self.color,self.hitbox)
self.hitbox = (self.x + 35, self.y + 0, 40, 40)
# calling the balloon and balloon2 in and image list
if self.direction == "balloon":
image_list = self.balloon
elif self.direction == "pop":
image_list = self.balloon2
# Is it time to show next frame
time_now = pygame.time.get_ticks()
if (time_now > self.next_frame_time):
# Time until the next game
inter_time_delay = 1000 // self.fps
self.next_frame_time = time_now + inter_time_delay
# Showing next frame
self.anim_index += 1
if self.anim_index >= len(image_list):
self.anim_index = 0
if self.anim_index >= len(image_list):
self.anim_index = 0
balloon_image = image_list[self.anim_index]
rectt = balloon_image.get_rect(center = self.get_rect().center)
rectt.centerx
rectt.centery += 5
window.blit(balloon_image,rectt)
# The color white
white = (255,255,255)
# The xy cords, width, height and color of my classes[]
playerman = Player(350,385,34,75,white)
green1 = Balloon(180,200,BALLOON_W,BALLOON_H,white, "green")
blue1 = Balloon(330,250,BALLOON_W,BALLOON_H,white, "blue")
orange1 = Balloon(100,200,BALLOON_W,BALLOON_H,white, "orange")
pink1 = Balloon(300,250,BALLOON_W,BALLOON_H,white, "pink")
purple1 = Balloon(400,250,BALLOON_W,BALLOON_H,white, "purple")
red1 = Balloon(300,200,BALLOON_W,BALLOON_H,white, "red")
# A list for my classess
balloons = [green1, blue1, orange1, pink1, purple1, red1]
# This is where my balloons get hit by the bullet and disappers
# redrawing window
def redrawwindow():
window.fill((0,0,0))
# Drawing the window in
window.blit(background,(0,0))
# drawing the player in window
playerman.draw()
# Drawing all my ballons in window
for balloon in balloons:
balloon.draw()
# Drawing the players bullet
for bul in bullets:
bul.draw()
def create_new_balloon():
global balloons
# create new balloon randomly
balloon_type = random.randint(0,5) # 0 = green, 1 = blue, ...
x, y = random.randint(X_MIN,X_MAX), random.randint(Y_MIN, Y_MAX)
if(balloon_type == 0):
new_bal = Balloon(x, y, BALLOON_W, BALLOON_H, white, "green")
if(balloon_type == 1):
new_bal = Balloon(x, y, BALLOON_W, BALLOON_H, white, "blue")
if(balloon_type == 2):
new_bal = Balloon(x, y, BALLOON_W, BALLOON_H, white, "red")
if(balloon_type == 3):
new_bal = Balloon(x, y, BALLOON_W, BALLOON_H, white, "pink")
if(balloon_type == 4):
new_bal = Balloon(x, y, BALLOON_W, BALLOON_H, white, "purple")
if(balloon_type == 5):
new_bal = Balloon(x, y, BALLOON_W, BALLOON_H, white, "orange")
balloons.append(new_bal)
def move_balloons_down():
global balloons
for balloon in balloons:
balloon.y += BALLOONS_Y_INCREMENT
# Frames for game
fps = 30
clock = pygame.time.Clock()
#projectile empty list
bullets = []
# main loop
run = True
while run:
clock.tick(fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if len(bullets) < 6700:
mousex, mousey = pygame.mouse.get_pos()
start_x, start_y = playerman.get_top()
mouse_x, mouse_y = event.pos
dir_x, dir_y = mouse_x - start_x , mouse_y - start_y
distance = math.sqrt(dir_x**2 + dir_y**2)
if distance > 0:
new_bullet = projectile(start_x, start_y, dir_x/distance, dir_y/distance, (0,0,0))
bullets.append(new_bullet)
for bullet in bullets:
bullet.move()
if bullet.x < 0 or bullet.x > 900 or bullet.y < 0 or bullet.y > 900:
bullets.pop(bullets.index(bullet))
# Making game detect when to del the ballon
for bullet in bullets:
for balloon in balloons:
if bullet.rect.colliderect(balloon.hitbox):
for _ in range(N_NEW_BALLOONS):
create_new_balloon()
move_balloons_down()
balloon.direction = "pop"
if bullet in bullets:
bullets.pop(bullets.index(bullet))
for balloon in balloons:
for one in range(len(balloons)-1,-1,-1):
if balloons[one].anim_index == 5:
del balloons[one]
# I removed this line, I don't know why you want to delete balloons that overlap
#for i in range(len(balloons)):
# for j in range(i+1, len(balloons)):
# if balloons[i].rect.colliderect(balloons[j]):
# balloons[i].direction = "pop"
# balloons[j].direction = "pop"
# gun rotation
mousex, mousey = pygame.mouse.get_pos()
if not playerman.isLookingAtPlayer:
playerman.lookAt((mousex, mousey))
# telling game that key means when a key get pressed
keys = pygame.key.get_pressed()
# The player moving when the key a is pressed
if keys[pygame.K_a] and playerman.x > playerman.speed:
playerman.x -= playerman.speed
# The player moving when the key d is pressed
if keys[pygame.K_d] and playerman.x < 500 - playerman.width - playerman.speed:
playerman.x += playerman.speed
# Calling the redraw function
redrawwindow()
# updating game
pygame.display.update()
# quiting the game
pygame.quit()
Let me know if you have other questions, cheers

Make bullets fire off in the direction the player is facing

I was just getting some help to figure out how to get my player fire bullets when I realized that they only go (kinda expected this but however as only had y value for movement). I don't know how I'll make the bullets fire off in the direction the player is facing.
I have some idea of what to but I just don't know how to do it... I thought I could somehow use the cursor and player tracking that's in this game for the visuals but I don't know how to make that a one-time thing instead of a constant. For diagonal movement of the bullet, I have no clue.
Code below (split into two parts/file Main.py and PlayerSprite.py):
Main:
py.init()
py.mixer.init()
screen = py.display.set_mode((WIDTH, HEIGHT))
py.display.set_caption("Dimensional Drifter")
clock = py.time.Clock()
all_sprites = py.sprite.Group()
NPCs = py.sprite.Group()
bullets = py.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(14):
n = NPC(player)
all_sprites.add(n)
NPCs.add(n)
# Game loop
running = True
while running:
# keep loop running at the right speed
clock.tick(FPS)
for event in py.event.get():
# check for closing window
if event.type == py.QUIT:
running = False
elif event.type == py.KEYDOWN:
if event.key == py.K_SPACE:
New_bullet = player.Shoot()
all_sprites.add(New_bullet)
bullets.add(New_bullet)
# Update
all_sprites.update()
# # check if there a collision between the bullet and NPC
hits = py.sprite.groupcollide(NPCs, bullets, True, True)
# check if there a collision between the player and NPC
hits = py.sprite.spritecollide(player, NPCs, True)
if hits:
running = False
# updates the position of of mouse and rotates it towards the mouse position
mouse_x, mouse_y = py.mouse.get_pos()
player.rotate(mouse_x, mouse_y)
# render
screen.fill(BLACK)
all_sprites.draw(screen)
# flip the display
py.display.flip()
py.quit()
PlayerSprite
import pygame as py
import math
import random
WIDTH = 800
HEIGHT = 600
FPS = 60
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
class Player(py.sprite.Sprite):
def __init__(self):
py.sprite.Sprite.__init__(self)
self.image = py.Surface((40, 40), py.SRCALPHA)
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT / 2
self.Yspeed = 0
self.rotatableimage = self.image
def update(self):
self.Xspeed = 0
self.Yspeed = 0
# line below allow for key press to equate to move of sprite
keypreesed = py.key.get_pressed()
if keypreesed[py.K_a]:
self.Xspeed = - 11
if keypreesed[py.K_d]:
self.Xspeed = 11
if keypreesed[py.K_w]:
self.Yspeed = - 11
if keypreesed[py.K_s]:
self.Yspeed = 11
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
# line below allow the sprite to wrap around the screen
if self.rect.left > WIDTH:
self.rect.right = 0
if self.rect.right < 0:
self.rect.left = WIDTH
if self.rect.top > HEIGHT:
self.rect.top = 0
if self.rect.bottom < 0:
self.rect.bottom = HEIGHT
def rotate(self, mouse_x, mouse_y):
rel_x = mouse_x - self.rect.x
rel_y = mouse_y - self.rect.y
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
self.image = py.transform.rotate(self.rotatableimage, int(angle))
self.rect = self.image.get_rect(center=(self.rect.centerx, self.rect.centery))
return
def Shoot(self):
return Bullet(self.rect.centerx, self.rect.top)
class NPC(py.sprite.Sprite):
def __init__(self, player):
py.sprite.Sprite.__init__(self)
self.player = player
self.image = py.Surface((30, 30)).convert_alpha()
self.image.fill(RED)
self.originalimage = self.image
self.rect = self.image.get_rect()
self.spawn()
# allows of spawning from all four side of the screen and set the x, y speed and spawn position
def spawn(self):
self.direction = random.randrange(4)
if self.direction == 0:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.Xspeed = random.randrange(-2, 2)
self.Yspeed = random.randrange(4, 8)
elif self.direction == 1:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(HEIGHT, HEIGHT + 60)
self.Xspeed = random.randrange(-2, 2)
self.Yspeed = -random.randrange(4, 8)
elif self.direction == 2:
self.rect.x = random.randrange(-100, -40)
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.Xspeed = random.randrange(4, 8)
self.Yspeed = random.randrange(-2, 2)
elif self.direction == 3:
self.rect.x = random.randrange(WIDTH, WIDTH + 60)
self.rect.y = random.randrange(HEIGHT - self.rect.height)
self.Xspeed = -random.randrange(4, 8)
self.Yspeed = random.randrange(-2, 2)
def update(self):
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
# makes it so that NPC point to wards the player as it passes from side to side
dir_x, dir_y = self.player.rect.x - self.rect.x, self.player.rect.y - self.rect.y
self.rot = (180 / math.pi) * math.atan2(-dir_x, -dir_y)
self.image = py.transform.rotate(self.originalimage, self.rot)
# Respawns the NPC when they hit an side
if self.direction == 0:
if self.rect.top > HEIGHT + 10:
self.spawn()
elif self.direction == 1:
if self.rect.bottom < -10:
self.spawn()
elif self.direction == 2:
if self.rect.left > WIDTH + 10:
self.spawn()
elif self.direction == 3:
if self.rect.right < -10:
self.spawn()
class Bullet(py.sprite.Sprite):
def __init__(self, x, y):
py.sprite.Sprite.__init__(self)
self.image = py.Surface((5, 5))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.Yspeed = -10
def update(self):
self.rect.y += self.Yspeed
# kill if moved of screen
if self.rect.bottom > HEIGHT or self.rect.top < 0:
self.kill()
if self.rect.right > WIDTH or self.rect.left < 0:
self.kill()
Add 2 attributes self.lastX and self.lastY to the class Player and change the attributes when the player changes the direction:
class Player(py.sprite.Sprite):
def __init__(self):
# [...]
self.lastX = 0
self.lastY = -10
def update(self):
# [...]
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
if self.Xspeed != 0 or self.Yspeed != 0:
self.lastX = self.Xspeed
self.lastY = self.Yspeed
Add an argument Xspeed ans Yspeed to the class Bullet
class Bullet(py.sprite.Sprite):
def __init__(self, x, y, Xspeed, Yspeed):
py.sprite.Sprite.__init__(self)
self.image = py.Surface((5, 5))
self.image.fill(YELLOW)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.Xspeed = Xspeed
self.Yspeed = Yspeed
def update(self):
self.rect.x += self.Xspeed
self.rect.y += self.Yspeed
# [...]
Set the attributes when the bullet spawns
class Player(py.sprite.Sprite):
# [...]
def Shoot(self):
return Bullet(self.rect.centerx, self.rect.centery, self.lastX, self.lastY)
Alternatively it is also possible to set the speed dependent on the direction to the mouse cursor.
Get the position of the player and the mouse cursor and compute the x and y distance (Vector ):
pos = self.rect.center
mpos = py.mouse.get_pos()
vx = mpos[0] - pos[0]
vy = mpos[1] - pos[1]
If the mouse position and the bullet position are equal, that does not make any sense, thus the bullet is skipped
if vx == 0 and vy == 0:
return None
Of course this vector is far to long, if you would use it for the direction (Xspeed, Yspeed) directly, then the bullet would step to the mouse cursor in one turn.
In the following I use pygame.math.Vector2, because it provides the handy method scale_to_length, that scales a vector to a specified Euclidean length:
direction = py.math.Vector2(vx, vy)
direction.scale_to_length(10)
Now the x and y component of the vector contain the x and y component of the speed. Since the components are floating point values, they are round to integral values:
return Bullet(pos[0], pos[1], round(direction.x), round(direction.y))
Method Shoot:
class Player(py.sprite.Sprite):
# [...]
def Shoot(self):
pos = self.rect.center
mpos = py.mouse.get_pos()
vx, vy = mpos[0] - pos[0], mpos[1] - pos[1]
if vx == 0 and vy == 0:
return None
direction = py.math.Vector2(vx, vy)
direction.scale_to_length(10)
return Bullet(pos[0], pos[1], round(direction.x), round(direction.y))
Note, if you set the bullet dependent on the direction to the mouse cursor, then it may be useful to spawn the bullet by a mouse click:
while running:
# [...]
for event in py.event.get():
if event.type == py.QUIT:
# [...]
elif event.type == py.MOUSEBUTTONDOWN:
if event.button == 1:
New_bullet = player.Shoot()
if New_bullet:
all_sprites.add(New_bullet)
bullets.add(New_bullet)
You can use pygames Vector2 to move in any direction. You calculate the angle of the player you can use that.
class Player(py.sprite.Sprite):
def __init__(self):
...
self.angle = 0
def rotate(self, mouse_x, mouse_y):
...
self.angle = -angle #make negative otherwise it will be going away from mouse
def Shoot(self):
return Bullet(self.rect.centerx, self.rect.top, py.math.Vector2(1,0).rotate(self.angle))
then in your bullet class, get the direction and add to its position
class Bullet(py.sprite.Sprite):
def __init__(self, x, y, Dir):
...
self.Dir = Dir
def update(self):
self.rect.y += self.Dir[1] * self.speed
self.rect.x += self.Dir[0] * self.speed
...

Bouncing pygame mask object on walls

I am rewriting a simple game. Before I just used e.g. pygame.draw.circle() to create and interact with objects.
However, there was a need to use masks for more complex tasks (like collision with polygons).
This is how I let the ball bounce on walls before:
def bounce(self):
# Right boundary
if self.x > width - self.radius:
self.x = 2 * (width - self.radius) - self.x
self.angle = - self.angle
self.velocity = Vector2(self.velocity) * elasticity
# Left boundary
elif self.x < self.radius:
self.x = 2 * self.radius - self.x
self.angle = - self.angle
self.velocity = Vector2(self.velocity) * elasticity
# Top boundary
if self.y > height - self.radius:
self.y = 2 * (height - self.radius) - self.y
self.angle = math.pi - self.angle
self.velocity = Vector2(self.velocity) * elasticity
# Bottom boundary
elif self.y < self.radius:
self.y = 2 * self.radius - self.y
self.angle = math.pi - self.angle
self.velocity = Vector2(self.velocity) * elasticity
But now with masks implemented, it only stops when it hits the wall but doesn't bounce off anymore.
Full code:
import pygame
from pygame.math import Vector2
import math
width = 1150
height = 800
# Colors
GOLD = (255, 215, 0)
drag = 0.999 # Between 0 and 1
elasticity = 0.75 # Between 0 and 1
pygame.init()
screen = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
# Define game object class
class Circle:
def __init__(self, coordinates, velocity, angle, radius, objectColor):
self.x = coordinates[0]
self.y = coordinates[1]
self.velocity = velocity
self.angle = angle
self.radius = radius
self.objectColor = objectColor
self.initSurface = pygame.Surface((self.radius*2, self.radius*2), pygame.SRCALPHA)
self.rectangle = self.initSurface.get_rect(center=Vector2(self.x, self.y))
self.surface = self.initSurface
self.mask = None
self.draw()
def draw(self):
pygame.draw.circle(self.initSurface, self.objectColor, [self.radius, self.radius], self.radius)
self.mask = pygame.mask.from_surface(self.initSurface)
def move(self):
self.x += self.velocity[0]
self.y += self.velocity[1]
self.velocity = Vector2(self.velocity) * drag
self.rectangle.center = Vector2(self.x, self.y)
def bounce(self):
# Right boundary
if self.x > width - self.radius:
self.x = 2 * (width - self.radius) - self.x
self.angle = - self.angle
self.velocity = Vector2(self.velocity) * elasticity
# Left boundary
elif self.x < self.radius:
self.x = 2 * self.radius - self.x
self.angle = - self.angle
self.velocity = Vector2(self.velocity) * elasticity
# Top boundary
if self.y > height - self.radius:
self.y = 2 * (height - self.radius) - self.y
self.angle = math.pi - self.angle
self.velocity = Vector2(self.velocity) * elasticity
# Bottom boundary
elif self.y < self.radius:
self.y = 2 * self.radius - self.y
self.angle = math.pi - self.angle
self.velocity = Vector2(self.velocity) * elasticity
class Polygon:
def __init__(self, coordinates, velocity, angle, pointList, objectColor):
self.x = coordinates[0]
self.y = coordinates[1]
self.velocity = velocity
self.angle = angle
self.pointList = pointList
self.objectColor = objectColor
self.initSurface = pygame.Surface((max(self.pointList, key=lambda item: item[0])[0],
max(self.pointList, key=lambda item: item[1])[1]), pygame.SRCALPHA)
self.rectangle = self.initSurface.get_rect(center=Vector2(self.x, self.y))
self.surface = self.initSurface
self.mask = None
self.draw()
def draw(self):
pygame.draw.polygon(self.initSurface, self.objectColor, self.pointList)
self.mask = pygame.mask.from_surface(self.initSurface)
def move(self):
self.x += self.velocity[0]
self.y += self.velocity[1]
self.rectangle.center = Vector2(self.x, self.y)
def rotate(self, angle):
self.angle += angle
self.velocity.rotate_ip(-angle)
surface = pygame.transform.rotate(self.initSurface, self.angle)
self.rectangle = surface.get_rect(center=self.rectangle.center)
# We need a new mask after the rotation.
self.mask = pygame.mask.from_surface(surface)
self.surface = surface
# Colliding game object particles
def collide(p1, p2):
offset = p1.rectangle[0] - p2.rectangle[0], p1.rectangle[1] - p2.rectangle[1]
overlap = myBall.mask.overlap(p1.mask, offset)
if overlap:
p2.velocity = Vector2(p1.velocity) * 1.4
# Images
BG_IMG = pygame.Surface((1150, 800))
BG_IMG.fill((30, 120, 30))
# Init Ball and car (input)
myBall = Circle(Vector2(575, 400), Vector2(0, 0), 0, 60, GOLD)
myInput = Polygon(Vector2(470, 370), Vector2(3, 0), 0, [(0, 0), (50, 10), (50, 20), (0, 30)], GOLD)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
myInput.rotate(5)
elif keys[pygame.K_RIGHT]:
myInput.rotate(-5)
# Move the car
myInput.move()
# Move the ball
myBall.velocity *= .99 # Friction
myBall.move()
myBall.bounce()
# Car collision.
collide(myInput, myBall)
# Drawing
screen.blit(BG_IMG, (0, 0))
screen.blit(myBall.surface, myBall.rectangle)
screen.blit(myInput.surface, myInput.rectangle)
pygame.display.flip()
clock.tick(60)
pygame.quit()
What am I missing here? I can't see through anymore.
In the bounce method you make the the velocity smaller, you never flip it so, just add a minus sign and it should bounce back instead of moving slower and slower into the boundry
self.velocity = Vector2(-self.velocity) * elasticity

Categories

Resources