This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
i found this unfinished file in my files and now i need to finish it, only problem is idk really how do i detect collision with the bullet and the player thing and/or the bullet and the enemy thing, when the bullets collide with the enemy it still dies, i just don't remember how.
here's the code ig help thanks
import pygame, os, random,sys
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.x = x
self.y = y
self.vel = 4
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((20,20))
self.image.fill((255, 0, 0))
y = random.randrange (0, 480)
x = 400
self.rect = self.image.get_rect(topleft = (x, y))
self.speed = random.randrange(1,2)
player = Player(x, y, width, height)
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
score = 0
# main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(bullets) < 8:
bullet = B(player.rect.centerx, player.rect.centery, 2, (0,0,0))
bullets.add(bullet)
all_sprites.add(bullet)
if len(enemies) < 2:
e = Enemy()
enemies.add(e)
all_sprites.add(e)
for bullet in bullets:
if bullet.rect.right < 500:
bullet.rect.x += bullet.vel
else:
bullet.kill()
for enemy in enemies:
if enemy.rect.right > 0:
enemy.rect.x -= enemy.speed
else:
enemy.kill()
print ("L")
pygame.quit()
sys.exit()
pygame.sprite.groupcollide(bullets, enemies, True, True)
keys = pygame.key.get_pressed()
if keys[pygame.K_UP] and player.rect.top > player.vel:
player.rect.y -= player.vel
if keys[pygame.K_DOWN] and player.rect.bottom < 500 - player.vel:
player.rect.y += player.vel
SCREEN.fill((190, 232, 220))
all_sprites.draw(SCREEN)
pygame.display.update()
pygame.quit()
Collision detection depends on your needs.
Bounding boxes are simple and can detect if the x, y edges of each object are not within one another. This is fine for fast moving games and things where you don't necessarily require point precision.
Distance vectors are also simple and perfect solution for circle collisions. They calculate the difference in distance between two objects according to a radius prescribed with the hypotenuse of distX^2 + distY^2.
Compound bounding objects are harder to calculate, especially for concave areas on objects of arbitrary shape. There are too many notable and novel approaches to collision detection beyond these to remark on here.
They're also increasingly complex depending on things like variability (if they're deformable objects, if they have particle seams, etc and 2d vs 3d object collision can be vastly different worlds as well. There are tons of articles, but I'll post one with implementation here
Related
I get the error message 'Enemy' object has no attribute '_Sprite__g' and I have no idea how to use the sprite groups. I'm trying to get them to spawn randomly across the x-axis only.
import pygame, os, random
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(object):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
def draw(self,SCREEN):
SCREEN.blit(self.image, (self.x,self.y))
class B():
def __init__(self,x,y,radius, color):
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
def draw(self,SCREEN):
pygame.draw.circle(SCREEN, self.color, (self.x,self.y),self.radius)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.Surface((20,20))
self.x = random.randrange (0,400)
self.y = 500
self.speed = random.randrange(1,3)
def draw (self,SCREEN):
SCREEN.blit(self.image,(self.x,self.y))
player = Player(x, y, width, height)
bullets = []
enemies = pygame.sprite.Group()
# Main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for bullet in bullets:
if bullet.x < 450 and bullet.x >0:
bullet.x += bullet.vel
else:
bullets.pop(bullets.index(bullet))
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
if len(bullets)< 5:
bullets.append(B(round(player.x + player.width //2), round(player.y + player.height//2),3, (0,0,0)))
if keys[pygame.K_w] and player.y > 30 - player.width - player.vel:
player.y -= player.vel
if keys[pygame.K_s] and player.y < 500 - player.width - player.vel:
player.y += player.vel
SCREEN.fill((190, 232, 220))
player.draw(SCREEN)
for bullet in bullets:
bullet.draw(SCREEN)
for i in range (8):
e = Enemy()
enemies.add(e)
pygame.display.update()
pygame.quit()
the obects need to be derives from pygame.sprite.Sprite. The base class needs to be initialized as well. Use super() to delegate to the base class constructor. e.g.:
class Player(object):
def __init__(self,x,y,width,height):
super().__init__()
# [...]
pygame.sprite.Group.draw() and pygame.sprite.Group.update() are methods which are provided by pygame.sprite.Group.
The former delegates the to the update method of the contained pygame.sprite.Sprites - you have to implement the method. See pygame.sprite.Group.update():
Calls the update() method on all Sprites in the Group [...]
The later uses the image and rect attributes of the contained pygame.sprite.Sprites to draw the objects - you have to ensure that the pygame.sprite.Sprites have the required attributes. See pygame.sprite.Group.draw():
Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect. [...]
Therefore the Sprite class must have the attributes .rect and .image. However you don't need the draw method:
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
Create a transparent pygame.Surface with the SRCALPHA flag and draw a circle on it:
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
Add pygame.sprite.Groups for all sprites. add() the player, the enemies and bullets to the Groups:
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
for i in range (8):
e = Enemy()
enemies.add(e)
all_sprites.add(e)
Draw the Sprites in the all_sprites Group with pygame.sprite.Group.draw. Remove a Sprite (form all Groups) with kill:
while running:
# [...]
for bullet in bullets:
if 0 < bullet.rect.y < 500:
bullet.rect.y -= bullet.vel
else:
bullet.kill()
# [...]
all_sprites.draw(SCREEN)
Use the keyboard event instead of pygame.key.get_pressed() to fire a bullet. See How do I stop more than 1 bullet firing at once?:
The collision of the enemies and bullets can be detected with pygame.sprite.groupcollide(). When the doKill arguments are set True, the sprites will be automatically removed:
pygame.sprite.groupcollide(bullets, enemies, True, True)
Complete example:
import pygame, os, random
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((20,20))
self.image.fill((255, 0, 0))
y = random.randrange (0, 480)
x = 400
self.rect = self.image.get_rect(topleft = (x, y))
self.speed = random.randrange(1,3)
player = Player(x, y, width, height)
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
# Main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(bullets) < 5:
bullet = B(player.rect.centerx, player.rect.centery, 3, (0,0,0))
bullets.add(bullet)
all_sprites.add(bullet)
if len(enemies) < 8:
e = Enemy()
enemies.add(e)
all_sprites.add(e)
for bullet in bullets:
if bullet.rect.right < 500:
bullet.rect.x += bullet.vel
else:
bullet.kill()
for enemy in enemies:
if enemy.rect.right > 0:
enemy.rect.x -= enemy.speed
else:
enemy.kill()
pygame.sprite.groupcollide(bullets, enemies, True, True)
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and player.rect.top > player.vel:
player.rect.y -= player.vel
if keys[pygame.K_s] and player.rect.bottom < 500 - player.vel:
player.rect.y += player.vel
SCREEN.fill((190, 232, 220))
all_sprites.draw(SCREEN)
pygame.display.update()
pygame.quit()
Per the documentation:
"When subclassing the Sprite, be sure to call the base initializer before adding the Sprite to Groups."
So the first two lines of Enemy __init__() should be:
def __init__(self):
pygame.sprite.Sprite.__init__(self)
You also need to set a rect for the enemy:
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
This question already has answers here:
Pygame doesn't let me use float for rect.move, but I need it
(2 answers)
Closed 1 year ago.
I have written two versions of the same bouncing ball game. One is OOP based and one is procedural, and I would expect them to do the same thing. Except, the Object Oriented program behaves differently.
I don't know the best way to explain it but the procedural code 'bouncing' keeps the ball bouncing indefinitely and bouncing to the same height each time. But the OOP code 'bouncing' increases the bounce height on each consecutive bounce. Yet I cannot find a difference in the logic between them.
OOP code
import pygame, time
class Ball(pygame.sprite.Sprite):
def __init__(self, colour, radius):
super().__init__()
self.image = pygame.Surface([radius*2, radius*2])
self.colour = colour
self.radius = radius
pygame.draw.circle(self.image, self.colour, (radius, radius), self.radius)
self.rect = self.image.get_rect()
self.rect.x = 350
self.rect.y = 350
self.change_y = 0.5
self.vel_y = 0
def update(self):
self.vel_y += self.change_y
self.rect.y += self.vel_y
def bounce(self):
self.vel_y = self.vel_y * -1
self.rect.y += self.vel_y
def play_game():
all_sprites_list = pygame.sprite.Group()
ball_list = pygame.sprite.Group()
ball = Ball(WHITE, 10)
ball_list.add(ball)
all_sprites_list.add(ball)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
all_sprites_list.draw(screen)
for ball in ball_list:
if ball.rect.y > 690:
ball.bounce()
else:
ball.update()
pygame.display.update()
clock.tick(60)
BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)
BLUE = (0,255,0)
GREEN = (0,0,255)
pygame.init()
screen_width = 700
screen_height = 700
screen = pygame.display.set_mode([screen_width, screen_height])
clock = pygame.time.Clock()
play_game()
pygame.quit()
Procedural code
import pygame
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BROWN = (200, 100, 0)
pygame.init()
size = (700, 700)
screen = pygame.display.set_mode(size)
done = False
clock = pygame.time.Clock()
rect_x = 350
rect_y = 350
rect_changey = 0
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
pygame.draw.circle(screen, WHITE, [rect_x, rect_y], 10)
if (rect_y > 690):
rect_changey = rect_changey* -1
rect_y += rect_changey
else:
rect_changey = rect_changey + 0.5
rect_y += rect_changey
pygame.display.flip()
clock.tick(60)
pygame.quit()
Update: The ball.update() function is running 1 more time than the equivalent part of the code in the procedural code. Still dont know why though
rect_x and rect_y can store floating point values. However rect.x and rect.y cannot just store integral values.
Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.
The coordinates for Rect objects are all integers. [...]
The fraction part of the coordinates gets lost when the new position of the object is assigned to the Rect object. If this is done every frame, the position error will accumulate over time.
If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinates and assign it to the location (e.g. .topleft) of the rectangle:
x, y = # floating point coordinates
rect.topleft = round(x), round(y)
Ball class:
class Ball(pygame.sprite.Sprite):
def __init__(self, colour, radius):
super().__init__()
self.image = pygame.Surface([radius*2, radius*2])
self.colour = colour
self.radius = radius
pygame.draw.circle(self.image, self.colour, (radius, radius), self.radius)
self.rect = self.image.get_rect()
self.x = 350
self.y = 350
self.rect.x = self.x
self.rect.y = self.y
self.change_y = 0.5
self.vel_y = 0
def update(self):
self.vel_y += self.change_y
self.y += self.vel_y
self.rect.topleft = round(self.x), round(self.y)
def bounce(self):
self.vel_y = self.vel_y * -1
self.y += self.vel_y
self.rect.topleft = round(self.x), round(self.y)
This question already has answers here:
Pygame mask collision
(1 answer)
How can I made a collision mask?
(1 answer)
Closed 2 years ago.
I've been looking for days to find a solution but any of the other threads could help me.
I've been trying to make the sprite move over the background image. The background have transparent streets that should be the possible paths for the sprite.
I need to detect when the sprite collide with the other part of the background image that is not transparent. i tried perfect collision method but i don't think it's the right solution for my case because the background.rect doesn't make any sense.
I also tried the overlap method but it always return true.
The pictures are 32 bit depth and i'm calling convert_alpha()
class sprites(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.x = 200
self.y = 300
self.img= player_sprite
self.rect = player_sprite.get_rect()
self.mask = pygame.mask.from_surface(player_sprite)
def position(self):
dx = mouse_x-self.x
dy = self.y-mouse_y
d = float((dx**2+dy**2)**0.5)
displ_x = dx/d
displ_y = dy/d
self.x += displ_x
self.y += displ_y
if type(self.mask.overlap(object_background.mask,(0,0))):
self.x -= displ_x
self.y -= displ_y
class object_background_class(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.img = object_background_img
self.rect = object_background_img.get_rect()
self.mask = pygame.mask.from_surface(object_background_img.convert_alpha())
object_background = object_background_class()
player = sprites()
player.position() changes each time the coordinates of the sprite accordind to the mouse(x,y) and check if with the new x,y of the player make it collides with the background
game_state = False
while not game_state:
for e in pygame.event.get():
if e == pygame.QUIT:
game_state = True
if e.type == pygame.KEYDOWN and e.type == pygame.K_ESCAPE:
game_state = True
if e.type == pygame.KEYDOWN:
if e.key == 27:
game_state = True
mouse_x, mouse_y = pygame.mouse.get_pos()
player.position()
DISPLAYSURFACE.blit(color_background, (0, 0))
DISPLAYSURFACE.blit(player.img, (player.x, player.y))
DISPLAYSURFACE.blit(object_background.img, (0, 0))
pygame.display.flip()
The game screen is one big coordinate plane, just say if x, y coords of player go over or under whatever x,y coord threshold than do something
I also tried the overlap method but it always return true.
Of course. pygame.sprite.collide_mask() use the .rect and .mask attribute of the sprite object for the collision detection.
You have to update self.rect after moving the player and changing the self.x and self.y attribute of the player:
class sprites(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.x = 200
self.y = 300
self.img= player_sprite
self.rect = player_sprite.get_rect()
self.mask = pygame.mask.from_surface(player_sprite)
def position(self):
dx = mouse_x-self.x
dy = self.y-mouse_y
d = float((dx**2+dy**2)**0.5)
displ_x = dx/d
displ_y = dy/d
self.x += displ_x
self.y += displ_y
if type(self.mask.overlap(object_background.mask,(0,0))):
self.x -= displ_x
self.y -= displ_y
self.rect.topleft = (round(self.x), round(self.y)) # <--- THIS IS MISSING
Now you can use collide_mask:
if pygame.sprite.collide_mask(player, object_background):
# [...]
I am teaching a fortnightly coding class to a group of dozen super bright young enthusiasts. We have already covered OOP and created a text based adventure using OOP.
Now I am planning to teach PyGame and continue using objects, and I am wondering if games could be built in such a way where the code for each object is in a separate file?, this would be really neat and easier to build on.
Well For the code below I tried making separate files for each object. This was only partially successful because the draw method never works quite well, I believe the issue that I cannot have separate files referencing the same pygame screen.
import pygame
import random
import time
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0,0,255)
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
pygame.init()
class Paddle:
'''Class to keep players location'''
def __init__(self,x=350, y=480, width =70,height=20):
self.x = x
self.y = y
self.change_x = 0
self.change_y = 0
self.width = width
self.height = height
self.score = 0
def move(self):
self.x += self.change_x
self.y += self.change_y
def draw(self):
pygame.draw.rect(screen, BLUE, [self.x,self.y, self.width, self.height])
def check_collision(self,ball):
if ball.y>460:
if abs(35+ self.x - ball.x) < 30:
self.score += 1
ball.draw(BLUE)
ball.y = 0
ball.x = random.randint(0,650)
ball.change_y = random.randint(2,3+int(self.score/5))
class Ball:
"""Class to keep track of a ball's location and vector."""
def __init__(self,x=350,y=250,size=25):
self.x = x
self.y = y
self.change_x = 0
self.change_y = 0
self.size = size
def move(self):
self.x += self.change_x
self.y += self.change_y
def draw(self,colour = WHITE):
pygame.draw.circle(screen,WHITE, [self.x, self.y], self.size)
# Set the height and width of the screen
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Bouncing Balls")
done = False
clock = pygame.time.Clock()
screen.fill(BLACK)
ball = Ball()
player = Paddle()
ball.change_y = 2
ball.draw()
while not done:
screen.fill(BLACK)
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pass
if event.key == pygame.K_LEFT:
player.change_x = -5
if event.key == pygame.K_RIGHT:
player.change_x = 5
else:
ball.change_x = 0
player.change_x = 0
if ball.y > 500:
print('YOUR SCORE: ',player.score)
time.sleep(2)
pygame.quit()
#move ball and player and check if they collide
ball.move()
player.move()
player.check_collision(ball)
#draw ball and player
ball.draw()
player.draw()
#render frame
clock.tick(60)
pygame.display.flip()
# Print score and exit
print('YOUR SCORE: ',player.score)
pygame.quit()
When I had separate files this is the error that I got in relation to screen
line 20, in draw
pygame.draw.circle(screen,WHITE, [self.x, self.y], self.size)
NameError: name 'screen' is not defined
Add a surface argument to the draw() methods of the classes Paddle and Ball and draw the object on the surface which is passed to the method:
class Paddle:
# [...]
def draw(self, surface):
pygame.draw.rect(surface, BLUE, [self.x,self.y, self.width, self.height])
class Ball:
# [...]
def draw(self, surface, colour = WHITE):
pygame.draw.circle(surface, colour, [self.x, self.y], self.size)
Now you can draw the objects on any pygame.Surface you want, e.g. screen:
ball.draw(screen)
player.draw(screen)
I am working on a game in pygame, so far the player can walk around, 50 blue blocks spawn randomly on the screen and the player can walk around and shoot them, but there is one problem the player can only shoot up, I want the player to shoot towards the mouse but am having some trouble getting it to do this.
this is my code
import pygame
from pygame import *
import random
black = ( 0, 0, 0)
white = ( 255, 255, 255)
red = ( 255, 0, 0)
blue = ( 0, 0, 255)
player_x, player_y = 0, 0
move_player_x, move_player_y = 0, 0
class Block(pygame.sprite.Sprite):
def __init__(self, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 15])
self.image.fill(color)
self.rect = self.image.get_rect()
class Player(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 = player_x
self.rect.y = player_y
class Bullet(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5
pygame.init()
screen_width = 700
screen_height = 400
screen = pygame.display.set_mode([screen_width,screen_height])
all_sprites_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()
bullet_list = pygame.sprite.Group()
for i in range(50):
block = Block(blue)
block.rect.x = random.randrange(screen_width)
block.rect.y = random.randrange(350)
block_list.add(block)
all_sprites_list.add(block)
player = Player()
all_sprites_list.add(player)
done = False
clock = pygame.time.Clock()
score = 0
player.rect.y = 370
# -------- Main Program Loop -----------
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
bullet = Bullet()
bullet.rect.x = player.rect.x
bullet.rect.y = player.rect.y
all_sprites_list.add(bullet)
bullet_list.add(bullet)
if event.type== pygame.KEYDOWN:
if event.key==K_a:
move_player_x=-1
elif event.key==K_d:
move_player_x=+1
elif event.key==K_w:
move_player_y=-1
elif event.key==K_s:
move_player_y=+1
if event.type== pygame.KEYUP:
if event.key==K_a:
move_player_x=0
elif event.key==K_d:
move_player_x=0
elif event.key==K_w:
move_player_y=0
elif event.key==K_s:
move_player_y=0
# --- Game logic
all_sprites_list.update()
player_x += move_player_x
player_y += move_player_y
for bullet in bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, block_list, True)
for block in block_hit_list:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
score += 1
print( score )
if bullet.rect.y < -10:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
screen.fill(white)
all_sprites_list.draw(screen)
pygame.display.flip()
clock.tick(20)
pygame.quit()
so there the code, any help is much appreciated
here is what i came up with, I changed some code from an RPG me and a friend are making
Change your bullet class code to this:
class Bullet(pygame.sprite.Sprite):
def __init__(self, mouse, player):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([4, 10])
self.image.fill(black)
self.mouse_x, self.mouse_y = mouse[0], mouse[1]
self.player = player
self.rect = self.image.get_rect()
def update(self):
speed = 4.
range = 200
distance = [self.mouse_x - self.player[0], self.mouse_y - self.player[1]]
norm = math.sqrt(distance[0] ** 2 + distance[1] ** 2)
direction = [distance[0] / norm, distance[1 ] / norm]
bullet_vector = [direction[0] * speed, direction[1] * speed]
self.rect.x -= bullet_vector[0]
self.rect.y -= bullet_vector[1]
now it takes the players pos and the mouse click pos as arguments for the class
the math is a bit confusing but it basically take the vector from the two points and gets a direction and sends the bullet that way
when you create a new bullet instance call it like this:
bullet = Bullet(pygame.mouse.get_pos(), [player.rect.x, player.rect.y])
that way the class gets the two points when the mouse button is clicked!
when you run it you may notice that the bullet goes in the opposite direction of the mouse click thought that would add some challenge. You can change it if you need
P.S. the speed variable can be adjusted! Oh, and the math module needs to be imported