How do I make one Sprite move towards another in pygame/python - python
So I've been doing quite a lot of research on this question, and I still haven't been able to implement other people's solutions to solve mine. I'm trying to make the Mob2 class move towards the Player class. Any suggestions to my code, or even how to improve my code would be greatly appreciated :) BTW, the code I've written below has been made in Atom, if you have any questions I'll be around to answer them. Thank you all so much!!
# Pygame template - skeleton for a new pygame project
import pygame
import random
import math
from os import path
working_dir = path.dirname(__file__)
from pygame.locals import *
WIDTH = 1000
HEIGHT = 700
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)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Virus Invaders")
clock = pygame.time.Clock()
font_name = pygame.font.match_font('arial')
health = 4
def draw_text(surf, text, size, x, y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, WHITE)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
def newmob():
m = Mob()
all_sprites.add(m)
mobs.add(m)
def newmob2():
n = Mob2()
all_sprites.add(n)
mobs2.add(n)
def draw_health_bar(surf, x, y, health):
if health==4:
healthImage = healthSheet.get_image(0, 102, 176, 23)
screen.blit(healthImage, [50, 50])
if health==3:
healthImage = healthSheet.get_image(0, 128, 176, 23)
screen.blit(healthImage, [50, 50])
if health==2:
healthImage = healthSheet.get_image(0, 155, 176, 23)
screen.blit(healthImage, [50, 50])
if health==1:
healthImage = healthSheet.get_image(0, 182, 176, 23)
screen.blit(healthImage, [50, 50])
if health==0:
healthImage = healthSheet.get_image(0, 209, 176, 23)
screen.blit(healthImage, [50, 50])
class Player(pygame.sprite.Sprite):
def __init__(self, health):
pygame.sprite.Sprite.__init__(self)
self.image = dudeSpriteSheet.get_image(60, 0, 60, 60)
self.rect = self.image.get_rect()
self.radius = 25
#pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.centerx = 100
self.rect.centery = 400.5
self.speedx = 0
self.speedy = 0
self.health = health
def update(self):
self.speedx = 0
self.speedy = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_s]:
self.speedy = 4
if keystate[pygame.K_w]:
self.speedy = -4
if keystate[pygame.K_d]:
self.speedx = 4
if keystate[pygame.K_a]:
self.speedx = -4
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.right > WIDTH-80:
self.rect.right = WIDTH-80
if self.rect.left < 90:
self.rect.left = 90
if self.rect.bottom > HEIGHT-87:
self.rect.bottom = HEIGHT-87
if self.rect.top < 187:
self.rect.top = 187
def shoot(self, X, Y, direction):
if direction == 1:
self.image = dudeSpriteSheet.get_image(60, 0, 60, 60)
elif direction == 2:
self.image = dudeSpriteSheet.get_image(0, 0, 60, 60)
elif direction == 3:
self.image = dudeSpriteSheet.get_image(120, 0, 60, 60)
elif direction == 4:
self.image = dudeSpriteSheet.get_image(180, 0, 60, 60)
X = X+self.speedx
Y = Y+self.speedy
bullet = Bullet(self.rect.centerx, self.rect.centery, X, Y)
all_sprites.add(bullet)
bullets.add(bullet)
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = virus_img
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width * 0.85 / 2)
#pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = WIDTH - 200
self.rect.y = 400.5
self.speedx = random.randrange(-4, 4)
self.speedy = random.randrange(-4, 4)
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.bottom >= HEIGHT - 87:
self.speedy = -self.speedy
if self.rect.top <= 193:
self.speedy = -self.speedy
if self.rect.left <= 94:
self.speedx = -self.speedx
if self.rect.right >= WIDTH - 96:
self.speedx = -self.speedx
class Mob2(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = virus2_img
self.image.set_colorkey(WHITE)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width * 0.85 / 2)
pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = WIDTH - 200
self.rect.y = 300
self.rot = 0
self.speed = 3
def update(self, Player):
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, X, Y):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = 25
self.rect.bottom = y
self.rect.centerx = x
self.speedy = Y
self.speedx = X
def update(self):
self.rect.x += self.speedx
self.rect.y += self.speedy
# Kill if it moves off the top of the screen
if self.rect.bottom < 0 or self.rect.top > 700 or self.rect.right <
0 or self.rect.left > 1000:
self.kill()
class Spritesheet:
#Utility class for loading and parsing spritesheets
def __init__(self, filename):
self.spritesheet = pygame.image.load(filename).convert()
def get_image(self, x, y, width, height):
#Grab an image out of a larger spritesheet
image = pygame.Surface((width, height))
image.blit(self.spritesheet, (0, 0), (x, y, width, height))
image.set_colorkey(BLACK)
return image
# Load all game graphics
background = pygame.image.load(path.join(working_dir,
'GameScreen.png')).convert()
background_rect = background.get_rect()
player_img = pygame.image.load(path.join(working_dir,'dude.png')).convert()
virus_img =
pygame.image.load(path.join(working_dir,'badguy1.png')).convert()
bullet_img =
pygame.image.load(path.join(working_dir,'bullet.png')).convert()
dudeSpriteSheet = Spritesheet(path.join(working_dir,
'DudeSpriteSheet2.png'))
healthSheet = Spritesheet(path.join(working_dir, 'health.png'))
virus2_img =
pygame.image.load(path.join(working_dir,'badguy2(2).png')).convert()
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
mobs2 = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player(health)
all_sprites.add(player)
for i in range(8):
newmob()
newmob2()
score = 0
# Game loop
running = True
while running:
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
player.shoot(10, 0, 1)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_UP:
player.shoot(0, -10, 2)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN:
player.shoot(0, 10, 3)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
player.shoot(-10, 0, 4)
# Update
all_sprites.update()
#Check to see if bullet hits a mob
hits = pygame.sprite.groupcollide(mobs, bullets, True,
pygame.sprite.collide_circle)
for hit in hits:
score += 1
newmob()
# Check to see if a virus hits a player
hits = pygame.sprite.spritecollide(player, mobs, True,
pygame.sprite.collide_circle)
for hit in hits:
health -= 1
newmob()
if health <= 0:
running = False
# Draw / render
screen.fill(BLACK)
screen.blit(background, background_rect)
all_sprites.draw(screen)
draw_text(screen, str(score), 18, WIDTH / 2, 10)
draw_health_bar(screen, 5, 5, health)
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
First compare Mob.rect.x with Player.rect.x to see if it should move left or right, then do the same with rect.y to see if it should move up or down. The its simply getting Mob to move in that direction.
Related
Im stuck on doing an explosion animation for my cement block sprites [duplicate]
This question already exists: I want to do an explosion animation. I have 4 png files number 0 - 3. In my debris class I loaded them into an image list using a for loop [duplicate] Closed 1 year ago. I want to do an explosion animation. I have 4 png files number 0 - 3. In my debris class I loaded them into an image list using a for loop. Then I made an explosion function but when I load my pygame windows and start shooting my cement block sprites, my cement block sprites disappear which is fine but they don't do the exploding animation I want. How can I fix this problem. Would appreciate the help. My code: import random import pygame import pygame.freetype pygame.init() #screen settings WIDTH = 1000 HEIGHT = 400 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("AutoPilot") screen.fill((255, 255, 255)) #fps FPS = 120 clock = pygame.time.Clock() #load images bg = pygame.image.load('background/street.png').convert_alpha() # background bullets = pygame.image.load('car/bullet.png').convert_alpha() debris_img = pygame.image.load('debris/cement.png') #define game variables shoot = False #player class class Player(pygame.sprite.Sprite): def __init__(self, scale, speed): pygame.sprite.Sprite.__init__(self) self.bullet = pygame.image.load('car/bullet.png').convert_alpha() self.bullet_list = [] self.speed = speed #self.x = x #self.y = y self.moving = True self.frame = 0 self.flip = False self.direction = 0 self.score = 0 #load car self.images = [] img = pygame.image.load('car/car.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale))) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() self.update_time = pygame.time.get_ticks() self.movingLeft = False self.movingRight = False self.rect.x = 465 self.rect.y = 325 #draw car to screen def draw(self): screen.blit(self.image, (self.rect.centerx, self.rect.centery)) #move car def move(self): #reset the movement variables dx = 0 dy = 0 #moving variables if self.movingLeft and self.rect.x > 33: dx -= self.speed self.flip = True self.direction = -1 if self.movingRight and self.rect.x < 900: dx += self.speed self.flip = False self.direction = 1 #update rectangle position self.rect.x += dx self.rect.y += dy #shoot def shoot(self): bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction) bullet_group.add(bullet) #check collision def collision(self, debris_group): for debris in debris_group: if pygame.sprite.spritecollide(debris, bullet_group, True): debris.health -= 1 if debris.health <= 0: self.score += 1 debris.kill() #player stats def stats(self): myfont = pygame.font.SysFont('comicsans', 30) scoretext = myfont.render("Score: " + str(self.score), 1, (0,0,0)) screen.blit(scoretext, (100,10)) #bullet class class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 5 self.image = bullets self.rect = self.image.get_rect() self.rect.center = (x,y) self.direction = direction def update(self): self.rect.centery -= self.speed #check if bullet has gone off screen if self.rect.centery < 1: self.kill() #debris class class Debris(pygame.sprite.Sprite): def __init__(self,scale,speed): pygame.sprite.Sprite.__init__(self) self.scale = scale self.x = random.randrange(100,800) self.speed_y = 10 self.y = 15 self.speed = speed self.vy = 0 self.on_ground = True self.move = True self.health = 4 self.max_health = self.health self.alive = True self.velocity = random.randrange(1,2) self.speed_x = random.randrange(-3,3) self.moving_down = True #load debris self.image = debris_img self.rect = self.image.get_rect() self.rect.x = random.randrange(100, 800) self.rect.y = random.randrange(-150, -100) self.rect.center = (self.x,self.y) #load explosion self.images = [] for i in range(4): self.images.append(pygame.image.load(f'explosion/{i}.png')) self.index = 0 self.img = self.images[self.index] #spawn new debris def spawn_new_debris(self): self.rect.x = random.randrange(100, 800) self.rect.y = random.randrange(-150, -100) self.velocity = random.randrange(1, 2) self.speed_x = random.randrange(-3, 3) #respawn debris when they go of the screen def boundaries(self): if self.rect.left > WIDTH + 10 or self.rect.right < -10 or self.rect.top > HEIGHT + 10: self.spawn_new_debris() #update image def update(self): self.rect.y += self.velocity self.rect.x += self.speed_x self.boundaries() #make debris fall down def falldown(self): self.rect.centery += self.velocity if self.moving_down and self.rect.y > 350: self.kill() #explosion def explode(self): if self.max_health <= 0: self.index += 1 if self.index >= len(self.images): self.index = 0 self.img = self.images[self.index] ######################CAR/DEBRIS########################## player = Player(1,5) ########################################################## #groups bullet_group = pygame.sprite.Group() debris_group = pygame.sprite.Group() all_sprites = pygame.sprite.Group() for i in range(50): d = Debris(1,5) debris_group.add(d) all_sprites.add(d) #game runs here run = True while run: #draw street screen.blit(bg, [0, 0]) #update groups bullet_group.update() bullet_group.draw(screen) debris_group.update() debris_group.draw(screen) #draw car player.draw() player.move() player.collision(debris_group) player.stats() #update all sprites all_sprites.update() all_sprites.draw(screen) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False #check if key is down if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: run = False if event.key == pygame.K_a: player.movingLeft = True if event.key == pygame.K_d: player.movingRight = True if event.key == pygame.K_SPACE: player.shoot() shoot = True #check if key is up if event.type == pygame.KEYUP: if event.key == pygame.K_a: player.movingLeft = False if event.key == pygame.K_d: player.movingRight = False #update the display pygame.display.update() pygame.display.flip() clock.tick(FPS) pygame.quit()
Change image of character when travelled specific number of pixels
I am making a game in pygame. I want to change the image of the character whenever it moves a certain amount of pixels to make it seem like he's walking, but I can't really understand how to do that. Here's the code: import pygame import time BLACK = ( 0, 0, 0) WHITE = (255, 255, 255) RED = (255, 0, 0) GREY = (129, 129, 129) frame = 0 class SpriteSheet(object): def __init__(self, file_name): self.sprite_sheet = pygame.image.load(file_name).convert() def get_image(self, x, y, width, height, colour): image = pygame.Surface([width, height]).convert() image.set_colorkey(colour) image.blit(self.sprite_sheet, (0, 0), (x, y, width, height)) return image class Bomb(pygame.sprite.Sprite): change_x =0 change_y = 0 def __init__(self): super().__init__() sprite_sheet = SpriteSheet("Untitled.png") self.image = sprite_sheet.get_image(2, 2, 48, 48, WHITE) self.rect = self.image.get_rect() def move(self, y): self.rect.y += y if self.rect.y == 400: self.kill() class Soldier(pygame.sprite.Sprite): def __init__(self): self.change_x = 0 self.change_y = 0 self.direction = "R" super().__init__() self.walking_frames_l = [] self.walking_frames_r = [] sprite_sheet = SpriteSheet("Picture2.png") self.image = sprite_sheet.get_image(0, 0, 150, 205, GREY) self.walking_frames_l.append(self.image) self.image = sprite_sheet.get_image(233, 0, 140, 210, GREY) self.walking_frames_l.append(self.image) self.image = sprite_sheet.get_image(425, 5, 123, 210, GREY) self.walking_frames_l.append(self.image) self.image = sprite_sheet.get_image(0, 0, 150, 205, GREY) self.image = pygame.transform.flip(self.image, True, False) self.walking_frames_r.append(self.image) self.image = sprite_sheet.get_image(233, 0, 140, 210, GREY) self.image = pygame.transform.flip(self.image, True, False) self.walking_frames_r.append(self.image) self.image = sprite_sheet.get_image(425, 5, 123, 210, GREY) self.image = pygame.transform.flip(self.image, True, False) self.walking_frames_r.append(self.image) self.image = self.walking_frames_r[0] self.rect = self.image.get_rect() self.rect.y = 297 self.rect.x = 100 def move(self): self.rect.x += self.change_x def walk(self): global frame if self.change_x > 0: frame +=1 time.sleep(.1) if frame == 3: frame = 0 self.image = self.walking_frames_r[frame] def go_left(self): self.change_x = -6 def go_right(self): self.change_x = 6 def stop(self): self.change_x = 0 self.image = self.walking_frames_r[2] pygame.init() screen_width = 1000 screen_height = 500 screen = pygame.display.set_mode([screen_width, screen_height]) pygame.display.set_caption("Game") clock = pygame.time.Clock() done = False bomb = Bomb() soldier = Soldier() all_sprites = pygame.sprite.Group() all_sprites.add(bomb) all_sprites.add(soldier) while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: soldier.go_left() if event.key == pygame.K_RIGHT: soldier.go_right() if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT and soldier.change_x < 0: soldier.stop() if event.key == pygame.K_RIGHT and soldier.change_x > 0: soldier.stop() screen.fill(RED) all_sprites.draw(screen) bomb.move(2) soldier.move() soldier.walk() clock.tick(60) pygame.display.flip() pygame.quit() I also tried to change the image after a particular amount of time (This part): def walk(self): global frame if self.change_x > 0: frame +=1 time.sleep(.1) if frame == 3: frame = 0 self.image = self.walking_frames_r[frame] When I add time.sleep(.1) and try to move the character, it somehow affects the bomb. It moves 2 pixels, waits for .1 seconds and again moves 2 pixels. Is there any way I can do either of the things mentioned above (either change the image after a particular amount of time or after a specific amount of pixels travelled)? Please help. Thanks!
frame has to be an attribute of the Soldier class. Additionally you need an attribute for the number of pixels the player has moved: class Soldier(pygame.sprite.Sprite): def __init__(self): # [...] self.frame = 0 self.moved = 0 Add the absolute movement to self.moved. Increment frame when the movement exceeds a certain number of pixels (pixel_for_one_step ): class Soldier(pygame.sprite.Sprite): # [...] def walk(self): self.moved += abs(self.change_x) pixels_for_one_step = 60 if self.moved > pixels_for_one_step: self.moved -= pixels_for_one_step self.frame += 1 if self.frame >= len(self.walking_frames_r): self.frame = 0 self.image = self.walking_frames_r[self.frame] Complete example: import pygame BLACK = ( 0, 0, 0) WHITE = (255, 255, 255) RED = (255, 0, 0) GREY = (129, 129, 129) class SpriteSheet(object): def __init__(self, file_name): self.sprite_sheet = pygame.image.load(file_name).convert() def get_image(self, x, y, width, height, colour): image = pygame.Surface([width, height]).convert() image.set_colorkey(colour) image.blit(self.sprite_sheet, (0, 0), (x, y, width, height)) return image class Bomb(pygame.sprite.Sprite): change_x =0 change_y = 0 def __init__(self): super().__init__() sprite_sheet = SpriteSheet("Untitled.png") self.image = sprite_sheet.get_image(2, 2, 48, 48, WHITE) self.rect = self.image.get_rect() def move(self, y): self.rect.y += y if self.rect.y == 400: self.kill() class Soldier(pygame.sprite.Sprite): def __init__(self): self.change_x = 0 self.change_y = 0 self.direction = "R" super().__init__() self.walking_frames_l = [] self.walking_frames_r = [] sprite_sheet = SpriteSheet("Picture2.png") self.image = sprite_sheet.get_image(0, 0, 150, 205, GREY) self.walking_frames_l.append(self.image) self.image = sprite_sheet.get_image(233, 0, 140, 210, GREY) self.walking_frames_l.append(self.image) self.image = sprite_sheet.get_image(425, 5, 123, 210, GREY) self.walking_frames_l.append(self.image) self.image = sprite_sheet.get_image(0, 0, 150, 205, GREY) self.image = pygame.transform.flip(self.image, True, False) self.walking_frames_r.append(self.image) self.image = sprite_sheet.get_image(233, 0, 140, 210, GREY) self.image = pygame.transform.flip(self.image, True, False) self.walking_frames_r.append(self.image) self.image = sprite_sheet.get_image(425, 5, 123, 210, GREY) self.image = pygame.transform.flip(self.image, True, False) self.walking_frames_r.append(self.image) self.image = self.walking_frames_r[0] self.rect = self.image.get_rect() self.rect.y = 297 self.rect.x = 100 self.frame = 0 self.moved = 0 def move(self): self.rect.x += self.change_x def walk(self): self.moved += abs(self.change_x) pixels_for_one_step = 60 if self.moved > pixels_for_one_step: self.moved -= pixels_for_one_step self.frame += 1 if self.frame >= len(self.walking_frames_r): self.frame = 0 self.image = self.walking_frames_r[self.frame] def go_left(self): self.change_x = -6 def go_right(self): self.change_x = 6 def stop(self): self.change_x = 0 self.image = self.walking_frames_r[2] pygame.init() screen_width = 1000 screen_height = 500 screen = pygame.display.set_mode([screen_width, screen_height]) pygame.display.set_caption("Game") clock = pygame.time.Clock() done = False bomb = Bomb() soldier = Soldier() all_sprites = pygame.sprite.Group() all_sprites.add(bomb) all_sprites.add(soldier) while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: soldier.go_left() if event.key == pygame.K_RIGHT: soldier.go_right() if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT and soldier.change_x < 0: soldier.stop() if event.key == pygame.K_RIGHT and soldier.change_x > 0: soldier.stop() screen.fill(RED) all_sprites.draw(screen) bomb.move(2) soldier.move() soldier.walk() clock.tick(60) pygame.display.flip() pygame.quit()
I have problem with bullet motion in pygame
When i shot i can control bullet in a fly. How can i avoid it. I want to bullet moved and i can't control it. Maybe i should to fix my code. But i can't solved it. For example bullet fly to right but when i pressed keys K_LEFT the bullet changes route. import pygame pygame.init() #Frames FPS = 60 #Colors WHITE = (255, 255, 255) GREY = (105, 105, 105) BLACK = (0, 0, 0) GREEN = (0, 225, 0) #Screen size W = 1280 H = 680 #Player_img p_up = pygame.image.load('Assets/tanks/green/up1.png') p_d = pygame.image.load('Assets/tanks/green/down1.png') p_r = pygame.image.load('Assets/tanks/green/right1.png') p_l = pygame.image.load('Assets/tanks/green/left1.png') #Scale_img player_up = pygame.transform.scale(p_up, (40, 40)) player_d = pygame.transform.scale(p_d, (40, 40)) player_r = pygame.transform.scale(p_r, (40, 40)) player_l = pygame.transform.scale(p_l, (40, 40)) #Screen sf = pygame.display.set_mode((W, H)) pygame.display.set_caption('TanksX') sf.fill(WHITE) #Clock clock = pygame.time.Clock() #For Game Run = True last_move = 0 #Sprites init class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = player_up self.rect = self.image.get_rect() self.rect.centerx = W // 2 self.rect.y = H // 2 self.speedy = 2 self.speedx = 2 self.shoot_delay = 1000 self.last_shot = pygame.time.get_ticks() def update(self): global last_move if keys[pygame.K_UP]: self.image = pygame.transform.rotate(player_up, 360) self.rect.y -= self.speedy last_move = 1 elif keys[pygame.K_DOWN]: self.image = pygame.transform.rotate(player_up, 180) self.rect.y += self.speedy last_move = 2 elif keys[pygame.K_RIGHT]: self.image = pygame.transform.rotate(player_up, -90) self.rect.x += self.speedx last_move = 3 elif keys[pygame.K_LEFT]: self.image = pygame.transform.rotate(player_up, 90) self.rect.x -= self.speedx last_move = 4 if keys[pygame.K_SPACE]: self.shoot() def shoot(self): now = pygame.time.get_ticks() if now - self.last_shot > self.shoot_delay: self.last_shot = now bullet1 = Bullet(self.rect.centerx, self.rect.centery) all_sprites.add(bullet1) bullets.add(bullet1) class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) a = 10 b = 10 self.image = pygame.Surface((a, b)) self.rect = self.image.get_rect() self.rect.centerx = x self.rect.centery = y self.speedy = 10 self.speedx = 10 def update(self): global last_move if self.rect.x > W or self.rect.x < 0 or self.rect.y > H or self.rect.y < 0: self.kill() if last_move == 1: self.rect.y -= self.speedy if last_move == 2: self.rect.y += self.speedy if last_move == 3: self.rect.x += self.speedx if last_move == 4: self.rect.x -= self.speedx #Groups all_sprites = pygame.sprite.Group() players = pygame.sprite.Group() bullets = pygame.sprite.Group() #Sprites player1 = Player() #Add Sprites to Groups all_sprites.add(player1) players.add(player1) #Game while Run: keys = pygame.key.get_pressed() for i in pygame.event.get(): if i.type == pygame.QUIT: exit() all_sprites.draw(sf) all_sprites.update() pygame.display.flip() sf.fill(WHITE) clock.tick(FPS) Please help me i will be very gratefull. I'm new to a python and pygame. Thankyou
The movement of the bullet is not affected by the current movement of the player. Add the arguments speedx and speedy to the class Bullet: class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, speedx, speedy): pygame.sprite.Sprite.__init__(self) a = 10 b = 10 self.image = pygame.Surface((a, b)) self.rect = self.image.get_rect() self.rect.centerx = x self.rect.centery = y self.speedx = speedx self.speedy = speedy def update(self): if self.rect.x > W or self.rect.x < 0 or self.rect.y > H or self.rect.y < 0: self.kill() self.rect.x += self.speedx self.rect.y += self.speedy The movement of bullet depends on the direction of the player when the bullet is shot. Determine the movement of the bullet (speedx, speedy) in Player.shoot, dependent on last_move and pass the movement to the constructor of Bullet: class Player(pygame.sprite.Sprite): # [...] def shoot(self): now = pygame.time.get_ticks() if now - self.last_shot > self.shoot_delay: speedx, speedy = 10, 0 if last_move == 1: speedx, speedy = 0, -10 if last_move == 2: speedx, speedy = 0, 10 if last_move == 3: speedx, speedy = 10, 0 if last_move == 4: speedx, speedy = -10, 0 self.last_shot = now bullet1 = Bullet(self.rect.centerx, self.rect.centery, speedx, speedy) all_sprites.add(bullet1) bullets.add(bullet1)
How to keep a ball moving like in pong?
I'm creating a tennis game, similar to pong but will be much more similar to real tennis (i.e. ability to control the direction and type of your shot). I think I've got the collision detection with the ball and the player figured out, but when the player collides with the ball it moves a few pixels then stops. I need it to keep going like in pong. Not sure if the problem is with the collision detection or just with something else in the code. import pygame pygame.init() # Define some colors BLACK = (0, 0, 0) OUT = (193, 58, 34) COURT = (69, 150, 81) WHITE = (255, 255, 255) GREEN = (0, 255, 0) SKIN = (232, 214, 162) ballspeed = 2 # Create the screen windowsize = (700, 500) screen = pygame.display.set_mode(windowsize) pygame.display.set_caption('Tennis') # Player Sprites class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("Robert_tennis.png") self.rect = self.image.get_rect() self.rect.center = (360, 480) self.speedx = 0 self.speedy = 0 def update(self): self.speedx = 0 self.speedy = 0 keystate = pygame.key.get_pressed() if keystate[pygame.K_LEFT]: self.speedx = -4 if keystate[pygame.K_RIGHT]: self.speedx = 4 self.rect.x += self.speedx if self.rect.right > 700: self.rect.right = 700 if self.rect.right < 0: self.rect.left = 0 if keystate[pygame.K_UP]: self.speedy = -5 if keystate[pygame.K_DOWN]: self.speedy = 3 self.rect.y += self.speedy if self.rect.y < 235: self.rect.y = 235 if self.rect.y < 0: self.rect.y = 0 class Ball(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("tennisball.png") self.rect = self.image.get_rect() self.rect.center = (360, 325) def update(self): if tennisball.rect.colliderect(robert): self.rect.y -= 2 #Add myself all_sprites = pygame.sprite.Group() robert = Player() tennisball = Ball() all_sprites.add(robert) all_sprites.add(tennisball) carryOn = True clock = pygame.time.Clock() while carryOn: for event in pygame.event.get(): if event.type == pygame.QUIT: carryOn = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_x: carryOn = False all_sprites.update() # Fill the screen with a sky color screen.fill(OUT) # Draw the court pygame.draw.rect(screen, COURT, [175, 0, 350, 500]) pygame.draw.line(screen, WHITE, (170,500), (170,0), 10) pygame.draw.line(screen, WHITE, (520,500), (520,0), 10) pygame.draw.line(screen, WHITE, (170,130), (520,130), 10) pygame.draw.line(screen, WHITE, (170,370), (520,370), 10) pygame.draw.line(screen, WHITE, (340,130), (340,370), 10) pygame.draw.line(screen, BLACK, (170,250), (520,250), 10) # Update all_sprites.draw(screen) pygame.display.flip() clock.tick(60) pygame.quit()
When you do def update(self): if tennisball.rect.colliderect(robert): self.rect.y -= 2 then the ball moves only once. In that "moment" when the player hits the ball and the condition is fulfilled. After the ball has moved, the condition is not fulfilled any more and the ball stops. When the racket hits the ball then you've to change the speed of the ball rather than its position. Add attributes which store the speed of the ball (.speedx, .speedy). Initialize the attributes by 0. Continuously change the position of the ball by it speed in the method .update(). When the racket hits the ball then change the speed: e.g. class Ball(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("tennisball.png") self.rect = self.image.get_rect() self.rect.center = (360, 325) self.speedx = 0 self.speedy = 0 def update(self): if tennisball.rect.colliderect(robert): self.speedy = -2 self.rect = self.rect.move(self.speedx, self.speedy) Note, if there is a player at the other side of the court, which hits the ball, then the speed is changed again. The speed can also have an sideward component for a diagonal movement.
Bullet not colliding with enemy Pygame (Python 3)
I want to make a mega man similar game where you jump around and shooting stuff. But I've noticed there's something wrong with the collision, I have a video below: https://youtu.be/p2VCtbBkefo I'm planning to make this project open source, so anybody can customize it. Please don't steal this code, but you may use chunks of it to help you with something. because I haven't put it on GitHub publicly yet. main.py: import pygame as pg from player import * from settings import * from levels import * from block import * from enemy import * class Game: def __init__(self): pg.init() pg.mixer.init() self.screen = pg.display.set_mode((width, height)) pg.display.set_caption("wait until realesed.") self.clock = pg.time.Clock() self.enemiesList = [] self.running = True self.shootRight = True def loadLevel(self, level, enemies, group, group2, group3): for y in range(0, len(level)): for x in range(0, len(level[y])): if (level[y][x] == 1): blockList.append(Block(x*32, y*32)) group.add(Block(x*32, y*32)) group2.add(Block(x*32, y*32)) for amount in range(0, enemies): group2.add(FlyingEnemy(self)) group3.add(FlyingEnemy(self)) self.enemies.add(FlyingEnemy(self)) self.enemiesList.append(FlyingEnemy(self)) def new(self): self.platforms = pg.sprite.Group() self.all_sprites = pg.sprite.Group() self.enemies = pg.sprite.Group() self.bullets = pg.sprite.Group() self.player = Player() self.loadLevel(level1["platform"], level1["enemies"], self.platforms, self.all_sprites, self.enemies) self.all_sprites.add(self.player) self.run() def shoot(self): if self.shootRight: self.bullet = Bullet(self.player.rect.centerx, self.player.rect.centery) self.bullet.speed = 10 self.all_sprites.add(self.bullet) self.bullets.add(self.bullet) print(self.bullet) elif self.shootRight == False: self.bullet = Bullet(self.player.rect.centerx, self.player.rect.centery) self.bullet.speed = -10 self.all_sprites.add(self.bullet) self.bullets.add(self.bullet) print(self.bullet) def run(self): self.playing = True while self.playing: self.clock.tick(FPS) self.events() self.update() self.draw() def update(self): self.all_sprites.update() self.enemy_hits = pg.sprite.spritecollide(self.player, self.enemies, False) #print(enemy_hits) if self.enemy_hits: pass #print("hit") self.bullet_hits = pg.sprite.groupcollide(self.enemies, self.bullets, True, True) if self.bullet_hits: print(self.bullet_hits) pygame.quit() hits = pg.sprite.spritecollide(self.player, self.platforms, False) if hits: self.player.pos.y = hits[0].rect.top + 1 self.player.vel.y = 0 def events(self): for event in pg.event.get(): if event.type == pg.QUIT: if self.playing: self.playing = False self.running = false if event.type == pg.KEYDOWN: if event.key == pg.K_UP: self.player.jump() if event.key == pg.K_SPACE: self.shoot() if event.key == pg.K_RIGHT: self.shootRight = True if event.key == pg.K_LEFT: self.shootRight = False def draw(self): self.screen.fill((255, 255, 255)) self.all_sprites.draw(self.screen) pg.display.flip() def show_start_screen(self): pass def show_go_screen(self): pass g = Game() g.show_start_screen() while g.running: g.new() g.show_go_screen() pg.quit() """width = 800 height = 600 FPS = 60 pg.init() pg.mixer.init() screen = pg.display.set_mode((width, height)) pg.display.set_caption("doom room") clock = pg.time.Clock() running = True while running: for event in pg.event.get(): clock.tick(FPS) if event.type == pg.QUIT: running = false screen.fill((255, 255, 255)) pg.display.flip() pg.quit()""" import pygame class Bullet(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((20, 10)) self.image.fill((240, 43, 12)) self.rect = self.image.get_rect() self.rect.bottom = y self.rect.centerx = x self.speed = -10 def update(self): self.rect.x += self.speed if self.rect.bottom < 0: self.kill() player.py import pygame as pg from settings import * from laser import * vec = pg.math.Vector2 class Player(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((40, 40)) self.image.fill((80, 123, 255)) self.rect = self.image.get_rect() self.rect.center = (width / 2, height / 2) self.pos = vec(width / 2, height / 2) self.vel = vec(0, 0) self.acc = vec(0, 0) #self.vx = 0 #self.vy = 0 def jump(self): self.vel.y = -15 def update(self): self.acc = vec(0, player_gravity) keys = pg.key.get_pressed() if keys[pg.K_LEFT]: self.acc.x = -player_acc if keys[pg.K_RIGHT]: self.acc.x = player_acc self.acc.x += self.vel.x * player_friction self.vel += self.acc self.pos += self.vel + 0.5 * self.acc if self.pos.x > width: self.pos.x = 0 if self.pos.x < 0: self.pos.x = width if self.pos.y <= 0: self.pos.y += 15 self.rect.midbottom = self.pos enemy.py import pygame as pg from random import * from settings import * class FlyingEnemy(pg.sprite.Sprite): def __init__(self, game): pg.sprite.Sprite.__init__(self) self.game = game self.image = pg.Surface((45, 45)) self.image.fill((20, 203, 50)) self.rect = self.image.get_rect() self.rect.centerx = choice([-100, width + 100]) self.vx = randrange(4, 7) if self.rect.centerx > width: self.vx *= -1 self.rect.y = height / 4 self.rect.x = 0 self.vy = 0 self.dy = 0.5 def update(self): if self.rect.x > width: self.rect.x = 0 if self.rect.x < 0: self.rect.x = width self.rect.x += self.vx self.vy += self.dy if self.vy > 3 or self.vy < -3: self.dy *= -1 center = self.rect.center if self.dy < 0: pass #print("bobbed up") else: pass #print("bobbed down") settings.py import pygame blockList = [] player_acc = 1.0 player_friction = -0.12 player_gravity = 0.5 bullets = pygame.sprite.Group() true = True false = False width = 800 height = 600 FPS = 60 levels.py level1 = { "platform": [ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0], [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0], [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0], [0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], ], "enemies": 5 } block.py import pygame as pg class Block(pg.sprite.Sprite): def __init__(self, x, y): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((32, 32)) self.image.fill((0, 0, 0)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y Thanks all help is appreciated.
This part of the loadLevel method causes the problem: for amount in range(0, enemies): group2.add(FlyingEnemy(self)) group3.add(FlyingEnemy(self)) self.enemies.add(FlyingEnemy(self)) self.enemiesList.append(FlyingEnemy(self)) You're adding 4 different FlyingEnemy objects to these groups and the list (btw, the list is useless), so the sprites in the self.all_sprites group and in the self.enemies group are not the same. Since you're only updating the all_sprites and not the enemies, the sprites in the enemies group, which are used for the collision detection, stay at the left screen edge all the time and are also invisible, because you don't draw this group. To solve the problem, create one instance and add this instance to the two groups: for amount in range(0, enemies): enemy = FlyingEnemy(self) self.enemies.add(enemy) self.all_sprites.add(enemy) I found the bug by printing the rect of one enemy sprite in the self.enemies group. Then I checked the update method of this sprite, but it looked correct, so I went to the instantiation part in loadLevel and noticed the mistake.