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.

Categories

Resources