Change image of character when travelled specific number of pixels - python

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()

Related

How can I detect collision between two moving sprites?

I am trying to make it so when my player sprite collides with an enemy, the player is killed. However, my player only dies if the enemy happens to spawn at the same point as the player and not when the player moves about and touches another sprite on purpose.
Here is my code:
import math
from random import randint
import pygame
from pygame.math import Vector2
pygame.init()
screen = pygame.display.set_mode((600, 600))
screen_width = 600
screen_height = 600
black = (0, 0, 0)
pygame.display.set_caption("gang")
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((50, 30), pygame.SRCALPHA)
pygame.draw.polygon(self.image, pygame.Color('steelblue2'), [(0, 0), (50, 15), (0, 30)])
self.original_image = self.image
self.rect = self.image.get_rect(center=pos)
self.pos = Vector2(pos)
self.velocityx = Vector2(6, 0)
self.velocityy = Vector2(0, 6)
def update(self):
self.rect.center = (int(self.pos.x), int(self.pos.y))
clamp_rect = self.rect.clamp(screen.get_rect())
if clamp_rect != self.rect:
self.rect = clamp_rect
self.pos.x, self.pos.y = self.rect.center
self.rotate()
def rotate(self):
direction = pygame.mouse.get_pos() - self.pos
radius, angle = direction.as_polar()
self.image = pygame.transform.rotate(self.original_image, -angle)
self.rect = self.image.get_rect(center=self.rect.center)
class Enemy(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.fill((randint(0, 255), randint(0, 255), randint(0, 255)))
self.rect = self.image.get_rect(center=pos)
self.pos = Vector2(pos)
self.velocity = Vector2(1, 0)
def update(self):
self.pos += self.velocity
self.rect.center = self.pos
class Projectile(pygame.sprite.Sprite):
def __init__(self, pos):
super().__init__()
self.image = pygame.Surface((9, 15), pygame.SRCALPHA)
pygame.draw.circle(self.image, (0, 0, 0), (30, 50), 14)
self.rect = self.image.get_rect(center=pos)
self.pos = Vector2(pos)
self.velocityx = Vector2(9, 0)
self.velocityy = Vector2(0, 9)
def update(self):
self.pos += self.velocityx
self.rect.center = self.pos
def draw_window():
screen.fill((30, 30, 30))
all_sprites.update()
all_sprites.draw(screen)
bullets.update()
bullets.draw(screen)
pygame.display.update()
def xor(a, b):
if bool(a) != bool(b):
return True
else:
return False
def game_end():
pygame.font.init()
text = pygame.font.Font('freesansbold.ttf', 32)
text_surface = text.render('Game Over', False, (255, 255, 255))
text_rect = text_surface.get_rect()
text_rect.center = (86, 86)
screen.blit(text_surface, (172, 172))
pygame.display.update()
player = Player((300, 300))
projectile = Projectile((150, 150))
bullets = pygame.sprite.Group(projectile)
enemies_list = pygame.sprite.Group()
all_sprites = pygame.sprite.Group(player, projectile)
def collision():
score = 0
for i in range(5):
enemy = Enemy((randint(0, 600), randint(0, 600)))
enemies_list.add(enemy)
all_sprites.add(enemy)
collide_list = pygame.sprite.spritecollide(player, enemies_list, True)
for enemy in collide_list:
all_sprites.remove(player)
collision()
def main():
screen_rect = screen.get_rect()
run = True
while run:
clock.tick(60)
keys = pygame.key.get_pressed()
for e in pygame.event.get():
if e.type == pygame.QUIT:
run = False
if keys[pygame.K_SPACE]:
if len(bullets) < 5:
projectile.pos += projectile.velocityx
if xor(keys[pygame.K_a], keys[pygame.K_LEFT]):
player.pos -= player.velocityx
elif xor(keys[pygame.K_d], keys[pygame.K_RIGHT]):
player.pos += player.velocityx
elif xor(keys[pygame.K_w], keys[pygame.K_UP]):
player.pos -= player.velocityy
elif xor(keys[pygame.K_s], keys[pygame.K_DOWN]):
player.pos += player.velocityy
player.rect.clamp_ip(screen_rect)
draw_window()
main()
How can I make it so that a collision is detected and hence my player is removed from the game whilst the two sprites are moving?
You have to check if the player collides with an enemy in the main loop:
e.g.
run = True
hit_count = 0
while run:
# [...]
player.rect.clamp_ip(screen_rect)
collidelist = pygame.sprite.spritecollide(player, enemies_list, False)
if collidelist:
hit_count += 1
print("hit", hit_count)
draw_window()
If you want to fins initial enemy positions, which are not "on" the player, you've to check for collision of a new enemy and the player before you add it to enemies_list respectively all_sprites:
e.g.
def collision():
score = 0
while len(enemies_list) < 5:#
enemy = Enemy((randint(0, 600), randint(0, 600)))
if not pygame.sprite.collide_rect(enemy, player):
enemies_list.add(enemy)
all_sprites.add(enemy)

I can't move sprites in pygame

It's the first time I create a game with pygame and I find a logical error. This game consist in a sort of puzzle and to play it you have to click to the piece of puzzle then click on the area where you want it to move. When I try to run my code, sprites doesn't move. I tried to modify the function move(), but it didn't change anything. When I run the program and I selected and move the pieces of puzzle of the game they are drawing again by the computer but in the same position. They aren't moving at the coordinates that I write in the code.
import pygame
from pygame.locals import *
import sys
import os
width = 1100
hight = 700
square1 = (240, 45)
square2 = (25, 55)
square3 = (25, 245)
square4 = (248, 245)
coords1 = [800, 50]
coords2 = [550, 50]
coords3 = [550, 250]
coords4 = [810, 250]
pygame.init()
screen = pygame.display.set_mode((width, hight))
pygame.display.set_caption('Hidden Boys')
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
class Puzzle_piece(pygame.sprite.Sprite):
def __init__(self, image_file, location):
pygame.sprite.Sprite.__init__(self)
self.counter = 0
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
self.state = "still"
self.area = screen.get_rect()
self.angle = 0
self.movepos = [0, 0]
def updates(self, position):
self.rect = position
def move(self):
screen.blit(self.image, self.rect)
def rotate_right(self):
self.angle += -90
self.image = pg.transform.rotozoom(self.orig_image, self.angle, 1)
self.rect = self.image.get_rect(center = self.rect.center)
class Frame(pygame.sprite.Sprite):
def __init__(self, image_file = None, location = None, dim = screen, color = (250, 250, 250)):
pygame.sprite.Sprite.__init__(self) #call Sprite initializer
if image_file and location != None :
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
self.rect.left, self.rect.top = location
self.frame = pygame.Surface(dim.get_size())
self.frame = self.frame.convert()
self.frame.fill(color)
def create_text(dim, blitted, color = (0, 0, 0), font = "", msg = "", position = (width, hight), alias = True):
font = pygame.font.SysFont(font, dim)
text = font.render(msg, alias, color)
textpos = text.get_rect()
textpos.center = position
blitted.blit(text, textpos)
def create_frames(name = "frame0", dim = screen, color = (250, 250, 250), image ="" ):
name = pygame.Surface(dim.get_size())
name = name.convert()
name.fill(color)
return name, img
def blit_frames(frame, coords = (0, 0), image = None, image_rect = None):
if image and image_rect != None :
frame.blit(image, image_rect)
screen.blit(frame, coords)
pygame.display.update()
pygame.display.flip()
def draw_sprites(sprites, frame, group):
for x in range(len(sprites)):
screen.blit(frame, sprites[x].rect, sprites[x].rect)
sprites[x].image = pygame.transform.scale(sprites[x].image, (272, 272))
group.update()
group.draw(screen)
pygame.display.flip()
background = Frame()
Frame1 = Frame("images\\field1.png", [-20, 0])
Piece1 = Puzzle_piece("images\\piece11.png", coords1)
Piece2 = Puzzle_piece("images\\piece21.png", coords2)
Piece3 = Puzzle_piece("images\\piece31.png", coords3)
Piece4 = Puzzle_piece("images\\piece41.png", coords4)
sprites_group = [Piece1, Piece2, Piece3, Piece4]
Piece_sprites = pygame.sprite.RenderPlain(sprites_group)
create_text(font = "squared_display", dim = 120, msg = "HIDDEN BOYS", position = (width/2, hight/4), blitted = background.frame)
create_text(font = "squared_display", dim = 50, msg = "Click to start", position = (width/2, hight/2), blitted = background.frame)
def move_pieces(piece):
for event in pygame.event.get():
if pygame.mouse.get_pos() in square1:
piece.updates(square1)
piece.move()
if pygame.mouse.get_pos() in square2:
piece.updates(square2)
piece.move()
if pygame.mouse.get_pos() in square3:
piece.updates(square3)
piece.move()
if pygame.mouse.get_pos() in square4:
piece.updates(square4)
piece.move()
screen.blit(background.frame, (0, 0))
pygame.display.flip()
def main():
clock = pygame.time.Clock()
while True:
frame = 0
counter = 0
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
return
if event.type == pygame.MOUSEBUTTONDOWN:
if frame == 0:
blit_frames(Frame1.frame, Frame1.rect, image = Frame1.image, image_rect = Frame1.rect)
draw_sprites(sprites_group, Frame1.frame, Piece_sprites)
frame += 1
elif frame == 1:
if pygame.mouse.get_pos() in coords1:
Piece1.state = "selected"
Piece1.counter += 1
move_pieces(Piece1)
if pygame.mouse.get_pos() in coords2:
Piece2.state = "selected"
Piece2.counter += 1
move_pieces(Piece2)
if pygame.mouse.get_pos() in coords3:
Piece3.state = "selected"
Piece3.counter += 1
move_pieces(Piece3)
if pygame.mouse.get_pos() in coords4:
Piece4.state = "selected"
Piece4.counter += 1
move_pieces(Piece4)
if event.type == pygame.MOUSEBUTTONUP:
if pygame.mouse.get_pos() in coords1 or coords2 or coords3 or coords4:
if Piece1.counter % 2 != 0:
Piece1.state = "unselected"
if Piece2.counter % 2 != 0:
Piece2.state = "unselected"
if Piece3.counter % 2 != 0:
Piece3.state = "unselected"
if Piece4.counter % 2 != 0:
Piece4.state = "unselected"
pygame.display.update()
pygame.display.flip()
if __name__ == '__main__': main()
Your updates method assigns the the tuple position to the rect object. Instead, try:
def updates(self, position):
self.rect.x, self.rect.y = position

How do you isolate enemy sprites so that they disappear when going into a new room?

I've tried few methods such as coding the enemies in the room1 class but nothing seems to work, it either doesn't spawn the intended sprite at all or the sprite spawns but doesn't disappear, when I go into other rooms (unless I collide with it). This is my code, any help at all would be much appreciated!
Side note, I've also tried to apply a different background to each room but haven't had any luck either. What needs to be done to implement that?
import pygame
import random
# Define colours
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
PURPLE = (255, 0, 255)
# --- Classes
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
class Player(pygame.sprite.Sprite):
change_x = 0
change_y = 0
def __init__(self, filename, x, y):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.y = y
self.rect.x = x
def changespeed(self, x, y):
self.change_x += x
self.change_y += y
def move(self, walls):
self.rect.x += self.change_x
block_hit_list = pygame.sprite.spritecollide(self, walls, False)
for block in block_hit_list:
if self.change_x > 0:
self.rect.right = block.rect.left
else:
self.rect.left = block.rect.right
self.rect.y += self.change_y
block_hit_list = pygame.sprite.spritecollide(self, walls, False)
for block in block_hit_list:
if self.change_y > 0:
self.rect.bottom = block.rect.top
else:
self.rect.top = block.rect.bottom
class Enemy(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
class ProjectileUp(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.y -= 5
class ProjectileDown(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.y += 5
class ProjectileLeft(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.x -= 5
class ProjectileRight(pygame.sprite.Sprite):
def __init__(self, filename):
super().__init__()
self.image = pygame.image.load(filename).convert()
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
def update(self):
self.rect.x += 5
class Room(object):
wall_list = None
enemy_sprites = None
def __init__(self):
self.wall_list = pygame.sprite.Group()
self.enemy_sprites = pygame.sprite.Group()
class Room1(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, BLACK],
[0, 350, 20, 250, BLACK],
[780, 0, 20, 250, BLACK],
[780, 350, 20, 250, BLACK],
[20, 0, 760, 20, BLACK],
[20, 580, 760, 20, BLACK]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
self.enemy_sprites.add(Enemy("Judas.png"))
class Room2(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, BLACK],
[0, 350, 20, 250, BLACK],
[780, 0, 20, 250, BLACK],
[780, 350, 20, 250, BLACK],
[20, 0, 760, 20, BLACK],
[20, 580, 760, 20, BLACK]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
class Room3(Room):
def __init__(self):
super().__init__()
walls = [[0, 0, 20, 250, BLACK],
[0, 350, 20, 250, BLACK],
[780, 0, 20, 250, BLACK],
[780, 350, 20, 250, BLACK],
[20, 0, 760, 20, BLACK],
[20, 580, 760, 20, BLACK]
]
for item in walls:
wall = Wall(item[0], item[1], item[2], item[3], item[4])
self.wall_list.add(wall)
def main():
pygame.init()
screen = pygame.display.set_mode([800, 600])
pygame.display.set_caption('Labyrinth')
player = Player("Isaac.png", 50, 50)
all_sprites_list = pygame.sprite.Group()
all_sprites_list.add(player)
enemy_sprites = Enemy("Judas.png")
enemy_list = pygame.sprite.Group()
enemy_list.add(enemy_sprites)
all_sprites_list.add(enemy_sprites)
enemy_sprites.rect.x = 150
enemy_sprites.rect.y = 200
projectile_list = pygame.sprite.Group()
rooms = []
room = Room1()
rooms.append(room)
room = Room2()
rooms.append(room)
room = Room3()
rooms.append(room)
current_room_no = 0
current_room = rooms[current_room_no]
clock = pygame.time.Clock()
# Load background image
background_position = [0, 0]
background_image = pygame.image.load("Floor.png").convert()
done = False
# ---------- MAIN PROGRAM LOOP ---------- #
while not done:
# --- Event Processing ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Controls
elif event.type == pygame.KEYDOWN:
projectile = None
if event.key == pygame.K_UP:
projectile = ProjectileUp("LightningUp.png")
projectile.rect.x = player.rect.x+10
projectile.rect.y = player.rect.y-30
elif event.key == pygame.K_DOWN:
projectile = ProjectileDown("LightningDown.png")
projectile.rect.x = player.rect.x+10
projectile.rect.y = player.rect.y+50
elif event.key == pygame.K_LEFT:
projectile = ProjectileLeft("LightningLeft.png")
projectile.rect.x = player.rect.x-15
projectile.rect.y = player.rect.y+33
elif event.key == pygame.K_RIGHT:
projectile = ProjectileRight("LightningRight.png")
projectile.rect.x = player.rect.x+35
projectile.rect.y = player.rect.y+33
elif event.key == ord('a'):
player.changespeed(-7, 0)
elif event.key == ord('d'):
player.changespeed(7, 0)
elif event.key == ord('w'):
player.changespeed(0, -7)
elif event.key == ord('s'):
player.changespeed(0, 7)
if projectile:
all_sprites_list.add(projectile)
projectile_list.add(projectile)
elif event.type == pygame.KEYUP:
if event.key == ord('a'):
player.changespeed(7, 0)
elif event.key == ord('d'):
player.changespeed(-7, 0)
elif event.key == ord('w'):
player.changespeed(0, 7)
elif event.key == ord('s'):
player.changespeed(0, -7)
# --- Game Logic ---
all_sprites_list.update()
enemy_hit_list = pygame.sprite.spritecollide(player, enemy_list, True)
for projectile in projectile_list:
enemy_hit_list = pygame.sprite.spritecollide(projectile, enemy_list, True)
for enemy in enemy_hit_list:
projectile_list.remove(projectile)
player.move(current_room.wall_list)
if player.rect.x < -15:
if current_room_no == 0:
current_room_no = 2
current_room = rooms[current_room_no]
player.rect.x = 790
elif current_room_no == 2:
current_room_no = 1
current_room = rooms[current_room_no]
player.rect.x = 790
else:
current_room_no = 0
current_room = rooms[current_room_no]
player.rect.x = 790
if player.rect.x > 801:
if current_room_no == 0:
current_room_no = 1
current_room = rooms[current_room_no]
player.rect.x = 0
elif current_room_no == 1:
current_room_no = 2
current_room = rooms[current_room_no]
player.rect.x = 0
else:
current_room_no = 0
current_room = rooms[current_room_no]
player.rect.x = 0
# --- Drawing ---
screen.blit(background_image, background_position)
all_sprites_list.draw(screen)
current_room.wall_list.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()
I think you mean you want to permanently delete the enemy sprites from the enemy_sprites group in the room class. As an example, from room 1, self.enemy_sprites.add(Enemy("Judas.png")). If you wanted to delete that you could just do the same but change .add() to .remove(). So just type self.enemy_sprites.remove(Enemy("Judas.png")) You can only do this if the class that your in also inherits the properties of the Room class.
Hope that helped! :)

Determining a collision of an arching projectile with another sprite in Pygame

In pygame I have a projectile being shot from one character sprite to another which I would like to determine whether there is a collision or not. That is a collision between a shot projectile and another character I will call TRUMP. I have found an equation in a tutorial that is the best example of an arching trajectory that I can accomplish. If that equation could be helped it would be awesome.
def fireshell(self, elapsedTime):
fire = True
FPS = 60 # frames per second setting
fpsClock = pg.time.Clock()
print("fire", self.pos.x, self.pos.y)
fireX = int(self.pos.x)
fireY = int(self.pos.y)
print("fireX", fireX, "fireY", fireY, "elapsed time", elapsedTime)
power = elapsedTime*.0005
x = int(self.pos.x)
y = int(self.pos.y) - 100
while fire:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
quit()
pg.draw.circle(self.screen, RED, (x, y), 5)
x -= int(-(elapsedTime*6))
y += int((((x - fireX)*0.015)**2) - ((elapsedTime*2)/(12 - elapsedTime )))
print("X:", x,"Y:", y)
if y > HEIGHT or x > WIDTH:
fire = False
pg.display.update()
self.clock.tick(20)
My character sprite who I would like to check for collisions with the projectile is here:
class TRUMP(pg.sprite.Sprite):
def __init__(self, spritesheet, all_sprites, mudballGroup, jetsGroup):
pg.sprite.Sprite.__init__(self)
self.spritesheet = spritesheet
self.all_sprites = all_sprites
self.mudballGroup = mudballGroup
self.jetsGroup = jetsGroup
self.current_frame2 = 0
self.last_update2 = 0
self.load_images()
self.image = self.TRUMP_fingers_l
self.rect = self.image.get_rect()
self.rect.center = (WIDTH *3/4), (589)
self.rect.centerx = (WIDTH *3/4)
self.rect.centery = 589
self.rect.centerx = (WIDTH*5/6)
self.rect.centery = 589
self.pos = vec((WIDTH/2), (HEIGHT/2))
self.vel = vec(0, 0)
self.acc = vec(0, 0)
self.dir = 0
To get a ballistic trajectory, you can just add a GRAVITY constant to the y-value of the velocity vector each frame.
For the collision detection you can use pygame.sprite.spritecollide again (you already know how that works).
Here's a complete example:
import sys
import pygame as pg
GRAVITY = 3
class Player(pg.sprite.Sprite):
def __init__(self, pos, color):
super().__init__()
self.image = pg.Surface((50, 30))
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
self.pos = pg.math.Vector2(pos)
self.vel = pg.math.Vector2()
def update(self):
self.pos += self.vel
self.rect.center = self.pos
class Projectile(pg.sprite.Sprite):
def __init__(self, pos, color, target):
super().__init__()
self.image = pg.Surface((7, 5))
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
self.pos = pg.math.Vector2(pos)
direction = target - self.pos # Vector to the target.
# Normalize, then scale direction to adjust the speed.
self.vel = direction.normalize() * 33
def update(self):
self.pos += self.vel
self.vel.y += GRAVITY
self.rect.center = self.pos
if self.rect.y > 580:
self.kill()
class Game:
def __init__(self):
self.fps = 30
self.screen = pg.display.set_mode((800, 600))
pg.display.set_caption('Ballistic trajectory')
self.clock = pg.time.Clock()
self.bg_color = pg.Color(90, 120, 100)
self.green = pg.Color('aquamarine2')
self.blue = pg.Color(30, 90, 150)
self.font = pg.font.Font(None, 30)
self.player = Player((100, 300), self.green)
self.player2 = Player((400, 300), self.blue)
self.all_sprites = pg.sprite.Group(self.player, self.player2)
self.projectiles = pg.sprite.Group()
self.collisions = 0
self.done = False
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(self.fps)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
proj = Projectile(
self.player.rect.center, pg.Color('sienna2'), event.pos)
self.projectiles.add(proj)
self.all_sprites.add(proj)
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
self.player.vel.x = -3
if event.key == pg.K_d:
self.player.vel.x = 3
if event.key == pg.K_w:
self.player.vel.y = -3
if event.key == pg.K_s:
self.player.vel.y = 3
if event.type == pg.KEYUP:
if event.key == pg.K_a and self.player.vel.x == -3:
self.player.vel.x = 0
if event.key == pg.K_d and self.player.vel.x == 3:
self.player.vel.x = 0
if event.key == pg.K_w and self.player.vel.y == -3:
self.player.vel.y = 0
if event.key == pg.K_s and self.player.vel.y == 3:
self.player.vel.y = 0
def run_logic(self):
self.all_sprites.update()
hits = pg.sprite.spritecollide(self.player2, self.projectiles, True)
for collided_sprite in hits:
self.collisions += 1
def draw(self):
self.screen.fill(self.bg_color)
self.all_sprites.draw(self.screen)
txt = self.font.render('Collisions {}'.format(self.collisions), True, self.green)
self.screen.blit(txt, (20, 20))
pg.display.flip()
if __name__ == '__main__':
pg.init()
game = Game()
game.run()
pg.quit()
sys.exit()

How do I make one Sprite move towards another in pygame/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.

Categories

Resources