I am making the game Space Invaders in Pygame and I want to let the enemy shoot randomly at the player. At this moment I can only let the enemy shoot at the player by pressing the tab button. But it should do this automatically and with a random interval. How can I get this working, without needing to press tab?
Thanks.
import pygame, sys
from pygame.locals import *
import random
screenWidth = 800
screenHeight = 600
FPS = 60
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Space Invaders")
clock = pygame.time.Clock()
shipWidth = 67
#colors
black=(0,0,0)
blue=(0,0, 255)
green=(0,128,0)
red=(255,0,0)
white=(255,255,255)
yellow=(255,255,0)
def app_quit():
pygame.quit()
sys.exit("System exit.")
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("spaceship3.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.centerx = screenWidth / 2
self.rect.bottom = screenHeight - 10
def update(self):
self.speedx = 0
if event.type == KEYDOWN and event.key == K_LEFT:
self.speedx = -2
elif event.type == KEYDOWN and event.key == K_RIGHT:
self.speedx = 2
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.right = screenWidth
if self.rect.left < 0:
self.rect.left = 0
def shootPlayer(self):
bulletPlayer = BulletPlayer(self.rect.centerx, self.rect.top)
allSprites.add(bulletPlayer)
bulletsPlayer.add(bulletPlayer)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("enemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = random.randrange(0, 200)
self.speedx = random.randrange(1, 2)
def update(self):
self.rect.x += self.speedx
if self.rect.right > screenWidth:
self.rect.x = 0
self.rect.y = random.randrange(0, 250)
self.speedx = random.randrange(1, 3)
# if self.rect.x > screenWidth: #kill when of the screen
# self.kill()
def shootEnemy(self):
bulletEnemy = BulletEnemy(self.rect.centerx, self.rect.bottom)
allSprites.add(bulletEnemy)
bulletsEnemy.add(bulletEnemy)
class BulletPlayer(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bullet.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.kill()
class BulletEnemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("bulletenemy.png").convert()
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 2
def update(self):
self.rect.y += self.speedy
if self.rect.bottom > screenHeight:
self.kill()
class Wall(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("wall.png").convert()
self.rect = self.image.get_rect()
self.rect.center = 100, 300
allSprites = pygame.sprite.Group()
player = Player()
enemy = pygame.sprite.Group()
bulletsPlayer = pygame.sprite.Group()
bulletsEnemy = pygame.sprite.Group()
wall = Wall()
allSprites.add(player, enemy, bulletsPlayer, bulletsEnemy, wall)
for i in range(1):
e = Enemy()
allSprites.add(e)
enemy.add(e)
running = True
while True:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
running = False
app_quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shootPlayer()
if event.key == pygame.K_TAB:
random.choice(enemy.sprites()).shootEnemy()
allSprites.update()
hitplayer = pygame.sprite.spritecollide(player, bulletsEnemy, True)
if hitplayer:
running = app_quit()
hitenemy = pygame.sprite.groupcollide(enemy, bulletsPlayer, True, True)
if hitenemy:
running = app_quit()
screen.fill(black)
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
You need a random timer variable which you can decrement by the dt (delta time) each frame. When it's below zero, create a bullet instance, add it to the group and reset the timer. I use the random.uniform function here which gives you a float, but you could also use random.randrange or randint if you want ints. To get the delta time (the time since the last tick) just assign the value that clock.tick(fps) returns to a variable.
# The timer is the time in seconds until the enemy shoots.
timer = random.uniform(2, 6) # Random float between 2 and 6.
dt = 0
running = True
while True:
# Event handling omitted.
# Decrease the timer by the delta time.
timer -= dt
if timer <= 0: # Ready to fire.
# Pick a random enemy to get the x and y coords.
random_enemy = random.choice(enemy.sprites())
enemy_x, enemy_y = random_enemy.rect.center
# Create a bullet and add it to the sprite groups.
bullet = BulletEnemy(enemy_x, enemy_y)
allSprites.add(bullet)
enemy.add(bullet)
timer = random.uniform(2, 6) # Reset the timer.
# Collision detection and drawing omitted.
# clock.tick returns the time that has passed since the last frame.
dt = clock.tick(60) / 1000 # / 1000 to convert it to seconds.
One way to do it is to create a custom event and trigger it based off some conditions, such as time.
You can use pygame.event.Event() and pygame.event.post() to trigger an event manually instead of using the Tab key. To setup this event on time you can use pygame.time.set_timer(myEvent, time). After that your main loop just needs to check for the event with pygame.event.get().
There is a good example of how to use custom events in pygame here: PyGame Custom Event
The author's example is even a Space Invaders type game so it will be useful to look at how it is written.
Related
Im new to python and im currently making a simple pygame but I can not grasp the concept of sprites. I want to replace the moving block with a player icon that I created.
Do I need to make a group just for one object or is there a way just to add the player without any groups?
from pygame import sprite
import pygame, sys
from pygame.locals import*
from pynput.keyboard import Key, Controller
class Player(pygame.sprite.Sprite):
def __init__(self, picture_path):
super().__init__()
self.image = pygame.image.load(picture_path)
self.rect = self.image.get_rect()
def main():
pygame.init()
DISPLAY=pygame.display.set_mode((1280,720),0,32)
pygame.display.set_caption('Der Sammler')
WHITE=(255,255,255)
BLUE=(0,0,255)
DISPLAY.fill(WHITE)
x = 0
y = 0
velocity1 = 0
acceleration = 0.1
velocity = pygame.Vector2()
velocity.xy = 3, 0
player = Player("player.png")
while True:
pygame.draw.rect(DISPLAY, BLUE, (x,y,50,50))
x += velocity.x
if x+ 50 > DISPLAY.get_width():
velocity.x = -3
if x < 0:
velocity.x = 3
pressed_keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
DISPLAY.fill((255, 255, 255))
pygame.draw.rect(DISPLAY,BLUE, (x,y, 50, 50))
y += velocity1
velocity1 += acceleration
if pressed_keys[pygame.K_SPACE]:
velocity1 = -3
pygame.display.update()
pygame.time.delay(10)
main()
Add an update method to Player and put the movement and gravity algorithm in that method:
class Player(pygame.sprite.Sprite):
def __init__(self, picture_path):
super().__init__()
self.image = pygame.image.load(picture_path)
self.rect = self.image.get_rect()
self.velocity = pygame.Vector2(3, 0)
self.acceleration = 0.1
def update(self, dispaly):
pressed_keys = pygame.key.get_pressed()
self.rect.x += self.velocity.x
if self.rect.right >= dispaly.get_width():
self.velocity.x = -3
if self.rect.left < 0:
self.velocity.x = 3
self.rect.y += self.velocity.y
self.velocity.y += self.acceleration
if pressed_keys[pygame.K_SPACE]:
self.velocity.y = -3
Add the player to a pygame.sprite.Group:
sprites = pygame.sprite.Group(player)
Call sprites.update() and sprites.draw() in the application loop to update the position of the player and to move the player:
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
sprites.update(DISPLAY)
DISPLAY.fill((255, 255, 255))
sprites.draw(DISPLAY)
pygame.display.update()
Also see How can I add objects to a "pygame.sprite.Group()"?.
Complete example:
import pygame, sys
from pygame.locals import*
class Player(pygame.sprite.Sprite):
def __init__(self, picture_path):
super().__init__()
self.image = pygame.image.load(picture_path)
self.rect = self.image.get_rect()
self.velocity = pygame.Vector2(3, 0)
self.acceleration = 0.1
def update(self, dispaly):
pressed_keys = pygame.key.get_pressed()
self.rect.x += self.velocity.x
if self.rect.right >= dispaly.get_width():
self.velocity.x = -3
if self.rect.left < 0:
self.velocity.x = 3
self.rect.y += self.velocity.y
self.velocity.y += self.acceleration
if pressed_keys[pygame.K_SPACE]:
self.velocity.y = -3
if self.rect.bottom > dispaly.get_height():
self.rect.bottom = dispaly.get_height()
self.velocity.y = 0
def main():
pygame.init()
DISPLAY=pygame.display.set_mode((1280,720),0,32)
pygame.display.set_caption('Der Sammler')
clock = pygame.time.Clock()
WHITE=(255,255,255)
BLUE=(0,0,255)
DISPLAY.fill(WHITE)
player = Player("player.png")
sprites = pygame.sprite.Group(player)
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
sprites.update(DISPLAY)
DISPLAY.fill((255, 255, 255))
sprites.draw(DISPLAY)
pygame.display.update()
clock.tick(100)
main()
This question already has answers here:
How can i shoot a bullet with space bar?
(1 answer)
How do I stop more than 1 bullet firing at once?
(1 answer)
Closed 10 months ago.
Im continuing practicing in pygame, and now the problem is that collisions between player and enemy dont work and player doesnt shoot. I watched at least 5 or 6 guides, googled, but it just doesnt work in my case. Game works even after player and enemy collide, and shoot when i shoot nothing happens.
import pygame, random
pygame.init()
pygame.font.init()
width, height = 924, 500
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Priest Beast')
clock = pygame.time.Clock()
BG = pygame.transform.scale2x(pygame.image.load('art/background.png')).convert_alpha()
music = pygame.mixer.Sound('sound/music.mp3')
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.transform.scale2x(pygame.image.load('art/Player.png')).convert_alpha()
self.x = x
self.y = y
self.rect = self.image.get_rect(center = (800, 300))
def move(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
self.rect.x -= 3
if keys[pygame.K_d]:
self.rect.x += 3
if self.rect.x >= 810:
self.rect.x = 810
if self.rect.x <= -30:
self.rect.x = -30
if keys[pygame.K_SPACE]:
self.shoot
def shoot(self):
bullet = Bullet(self.x, self.y)
bullets.add(bullet)
def update(self):
self.move()
self.shoot()
class Enemy(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.transform.scale2x(pygame.image.load('art/Enemy.png'))
self.image.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def move(self):
self.rect.x += 3
if self.rect.x >= 900:
self.kill
def update(self):
self.move()
class Bullet(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.image.load("art/bullet.png").convert_alpha()
self.rect = self.image.get_rect()
self.x = x
self.y = y
self.speed = -10
def update(self):
self.rect.x -= self.speed
if self.rect.x <= -100:
self.kill()
player = pygame.sprite.GroupSingle(Player(800,200))
enemy_list = pygame.sprite.Group()
obstacle_timer = pygame.USEREVENT + 1
timer = pygame.time.set_timer(obstacle_timer,4000)
bullets = pygame.sprite.Group()
hit = pygame.sprite.groupcollide(player, enemy_list, False, False)
bullethit = pygame.sprite.groupcollide(bullets, enemy_list, False, False)
#Loop and exit
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == obstacle_timer:
enemy_list.add(Enemy(random.randint(-1000, -30), 210))
if event.type == hit:
running = False
if event.type == bullethit:
print("hit!")
# Sounds
#music.play()
#music.set_volume(0.1)
screen.blit(BG, (0, 0))
enemy_list.draw(screen)
enemy_list.update()
bullets.update()
player.draw(screen)
player.update()
pygame.display.update()
clock.tick(60)
I've tried numerous things to let my bullets collide with my mob, but it doesn't work. The bullet just goes straight through the mob. I also tried spritecollide and groupcollide codes, but they all failed. Maybe i'm putting my code in the wrong line or the wrong place. I also want the bullet and mob to be removed from the list.
import pygame
import random
import math
GRAD = math.pi / 180
black = (0,0,0)
Bulleti = pygame.image.load('bullet.png')
Monster = pygame.image.load('Monster1re.png')
class Config(object):
fullscreen = True
width = 1366
height = 768
fps = 60
class Player(pygame.sprite.Sprite):
maxrotate = 180
down = (pygame.K_DOWN)
up = (pygame.K_UP)
def __init__(self, startpos=(102,579), angle=0):
super().__init__()
self.pos = list(startpos)
self.image = pygame.image.load('BigShagHoofdzzz.gif')
self.orig_image = self.image
self.rect = self.image.get_rect(center=startpos)
self.angle = angle
def update(self, seconds):
pressedkeys = pygame.key.get_pressed()
if pressedkeys[self.down]:
self.angle -= 2
self.rotate_image()
if pressedkeys[self.up]:
self.angle += 2
self.rotate_image()
def rotate_image(self):
self.image = pygame.transform.rotate(self.orig_image, self.angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Mob(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.x = 1400
self.rect.y = random.randrange(500,600)
self.speedy = random.randrange(-8, -1)
def update(self):
self.rect.x += self.speedy
if self.rect.x < -100 :
self.rect.x = 1400
self.speedy = random.randrange(-8, -1)
class Bullet(pygame.sprite.Sprite):
"""This class represents the bullet."""
def __init__(self, pos, angle, image):
super().__init__()
self.image = image
self.image = pygame.transform.rotate(self.image, angle)
self.rect = self.image.get_rect()
speed = 15
self.velocity_x = math.cos(math.radians(-angle)) * speed
self.velocity_y = math.sin(math.radians(-angle)) * speed
self.pos = list(pos)
def update(self):
""" Move the bullet. """
self.pos[0] += self.velocity_x
self.pos[1] += self.velocity_y
self.rect.center = self.pos
player = Player()
#this is the mob group
mobs = []
for x in range(0,10):
mob = Mob(Monster)
mobs.append(mob)
print(mobs)
#sprite lists
bullet_list = pygame.sprite.Group()
all_sprites_list = pygame.sprite.Group()
allgroup = pygame.sprite.LayeredUpdates()
allgroup.add(player)
for mob in mobs:
all_sprites_list.add(mob)
def main():
#game
pygame.mixer.pre_init(44100, -16, 1, 512)
pygame.mixer.init()
pygame.init()
screen=pygame.display.set_mode((Config.width, Config.height),
pygame.FULLSCREEN)
background = pygame.image.load('BGGameBig.png')
sound = pygame.mixer.Sound("shoot2.wav")
clock = pygame.time.Clock()
FPS = Config.fps
mainloop = True
while mainloop:
millisecond = clock.tick(Config.fps)
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
mainloop = False
if event.key == pygame.K_SPACE: #Bullet schiet knop op space
# Pass the position and angle of the player.
bullet = Bullet(player.rect.center, player.angle,
Bulleti)
all_sprites_list.add(bullet)
bullet_list.add(bullet)
sound.play()
if event.key == pygame.K_ESCAPE:
mailoop = False
pygame.display.set_caption("hi")
allgroup.update(millisecond)
all_sprites_list.update()
for bullet in bullet_list:
if bullet.rect.x > 1380:
bullet_list.remove(bullet)
all_sprites_list.remove(bullet)
#this is the code for collission
hits = pygame.sprite.groupcollide(bullet_list, mobs, True, True)
screen.blit(background, (0,0))
allgroup.draw(screen)
all_sprites_list.draw(screen)
pygame.display.flip()
if __name__ == '__main__':
main()
pygame.quit()
if anyone could help me out on this one it would really be appreciated. I spent alot of time working on the solution but I haven't found any yet. Watched alot of youtubers and did the same thing but it just won't work.
I get a different error when I run the program, an AttributeError caused by this line hits = pygame.sprite.groupcollide(bullet_list, mobs, True, True). That happens because the mobs list should be a pygame.sprite.Group.
mobs = pygame.sprite.Group()
for x in range(0,10):
mob = Mob(Monster)
mobs.add(mob)
After I changed this part of the code, it worked correctly.
I'm trying to develop a Brick Breaker/Breakout game using pygame, but I'm facing a annoying problem that blots the "ball" on the paddle(player) when I move with the arrows, i'm lefting the code for you to have a look.
import pygame
pygame.init()
isRunning = True
WIDTH = 800
HEIGHT = 600
FPS = 60
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIDTH, HEIGHT))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((60, 30))
self.image.fill((200, 255, 200))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 30
def update(self):
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_a]:
self.speedx = -5
if keystate[pygame.K_d]:
self.speedx = 5
self.rect.x += self.speedx
if self.rect.right + self.speedx > WIDTH:
self.rect.right = WIDTH
if self.rect.left + self.speedx < 0:
self.rect.left = 0
ball = Ball(self.rect.centerx, self.rect.top)
for i in all_sprites:
print(i)
all_sprites.add(ball)
def shoot(self):
ball = Ball(self.rect.centerx, self.rect.top)
all_sprites.add(ball)
balls.add(ball)
class Ball(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill((100, 150, 200))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
pass
#self.rect.y += self.speedy
all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
while isRunning:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
isRunning = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
window.fill((0, 0, 30))
all_sprites.update()
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
quit()
I'm not sure if I understand your question, but the problem with the code is that you're creating a ball every time you're updating the player. Just remove the last four lines in the player update method and uncomment the line in the ball's update method and everything works as it should.
Additional tips
Delete the balls when they exit the screen. This will prevent the game from running slow or crashing. It can be don by adding if self.rect.bottom < 0: self.kill() in the ball update method.
Use elif when appropriate.
In the player update method you define an attribute self.speedx which is only used inside that method, thus it's better to just use a local variable instead. Also, it's discourage to define attributes outside the __init__ method.
Here's your code slightly modified.
import pygame
pygame.init()
is_running = True # Use lowercase_and_underscore for variable names.
WIDTH = 800
HEIGHT = 600
FPS = 60
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIDTH, HEIGHT))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((60, 30))
self.image.fill((200, 255, 200))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 30
def update(self):
speedx = 0 # Don't define attributes outside __init__. Local variable works in this case instead.
keystate = pygame.key.get_pressed()
if keystate[pygame.K_a]:
speedx = -5
elif keystate[pygame.K_d]: # Use elif so it doesn't need to check this condition if the above is true.
speedx = 5
self.rect.x += speedx
if self.rect.right + speedx > WIDTH:
self.rect.right = WIDTH
elif self.rect.left + speedx < 0: # Use elif so it doesn't need to check this condition if the above is true.
self.rect.left = 0
def shoot(self):
ball = Ball(self.rect.centerx, self.rect.top)
all_sprites.add(ball)
balls.add(ball)
class Ball(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill((100, 150, 200))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -3
def update(self):
if self.rect.bottom < 0: # Chack if the ball has exit above the screen.
self.kill() # If it has it should delete itself.
self.rect.y += self.speedy
all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
while is_running:
clock.tick(FPS)
print(all_sprites)
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
window.fill((0, 0, 30))
all_sprites.update()
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
quit()
EDIT: KEEPING THE BALL ON THE PADDLE AND LAUNCHING WITH SPACE
First you could create an attribute self.current_ball in the Player class which will reference the ball on the paddle. Then in the update method of the Player class you update the ball's position relative to the paddle.
To keep the ball at the paddle you have to change the ball's self.speedy to start at 0, otherwise it will move directly after being created. When you call the player.shoot() method you'll set self.speedy = -3 which will start the ball to move.
After it has been launched you just create a new ball on the paddle and repeat the same process.
import pygame
pygame.init()
is_running = True # Use lowercase_and_underscore for variable names.
WIDTH = 800
HEIGHT = 600
FPS = 60
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIDTH, HEIGHT))
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((60, 30))
self.image.fill((200, 255, 200))
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 30
self.current_ball = Ball(self.rect.centerx, self.rect.top)
all_sprites.add(self.current_ball)
balls.add(self.current_ball)
def update(self):
speedx = 0 # Don't define attributes outside __init__. Local variable works in this case instead.
keystate = pygame.key.get_pressed()
if keystate[pygame.K_a]:
speedx = -5
elif keystate[pygame.K_d]: # Use elif so it doesn't need to check this condition if the above is true.
speedx = 5
self.rect.x += speedx
if self.rect.right + speedx > WIDTH:
self.rect.right = WIDTH
elif self.rect.left + speedx < 0: # Use elif so it doesn't need to check this condition if the above is true.
self.rect.left = 0
self.current_ball.rect.midbottom = self.rect.midtop # Set the ball position relative to paddle position.
def shoot(self):
self.current_ball.speedy = -3 # The ball should start moving.
self.current_ball = Ball(self.rect.centerx, self.rect.top) # Create a new ball on the paddle.
all_sprites.add(self.current_ball)
balls.add(self.current_ball)
class Ball(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill((100, 150, 200))
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = 0 # The ball don't move from the beginning.
def update(self):
if self.rect.bottom < 0: # Chack if the ball has exit above the screen.
self.kill() # If it has it should delete itself.
self.rect.y += self.speedy
all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
while is_running:
clock.tick(FPS)
print(all_sprites)
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
window.fill((0, 0, 30))
all_sprites.update()
all_sprites.draw(window)
pygame.display.flip()
pygame.quit()
quit()
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