How do I make my player collide with objects? [duplicate] - python

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
import libraries and define variables
import pygame, sys
import math
#variables globales
pygame.init()
size = width, height = 1000,700
screen = pygame.display.set_mode(size)
white = 255,255,255
reloj = pygame.time.Clock()
x = 100
y = 550
canjump = False
level = 3
this is my player class
class Player:
x = 100
y = 550
jump = 0
change_x = 0
change_y = 0
ha_saltado = False
top = 550
plataformaTop = False
def __init__(self):
super().__init__()
square_size = 50,50
self.image = pygame.Surface((square_size))
self.image.fill(white)
#establecer referencia de la imagen
self.rect = self.image.get_rect()
self.impulso_salto = 10
draw my player with x and y coordinates
def dibujar(self):
self.x += self.change_x
self.rect.x = self.x + self.change_x
self.rect.y = self.y
screen.blit(self.image, (self.x,self.y))
#movimiento horizontal
change player coordinates
def derecha (self):
self.change_x = 5
def izquierda (self):
self.change_x = -5
def stop (self):
self.change_x = 0
gravity function
#gravedad
def grav(self):
if self.ha_saltado:
if self.impulso_salto>= -10:
if self.impulso_salto < 0:
self.y += (self.impulso_salto ** 2)*0.5
else:
self.y -= (self.impulso_salto ** 2)*0.5
self.impulso_salto -= 1
else:
self.ha_saltado = False
canjump = False
self.impulso_salto = 10
def salto(self):
Player.grav(self)
def colisiones(self):
self.y += 2
if self.rect.colliderect(plataforma.rect):
self.plataformaTop = True
else:
self.plataformaTop = False
self.y -= 2
if self.plataformaTop:
print(plataforma.rect.top, self.y)
self.y -= 6
this is my stage class, here i make a white rectangle and i want my player can collide with the rectangle
class Escenario:
def __init__(self):
super().__init__()
here i create the rectangle
self.image = pygame.Surface([300,100])
self.image.fill(white)
self.rect = self.image.get_rect()
def dibujar(self, x, y):
screen.blit(self.image, (x, y))
self.rect.x = x
self.rect.y = y
here I create the events and initialize the objects
plataforma = Escenario()
player = Player()
texto = Texto()
pygame.mixer.music.load("C:/Users/Mati/Desktop/game/ost.mp3")
pygame.mixer.music.play()
while 1:
screen.fill((0,0,0))
player.colisiones()
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
player.derecha()
if event.key == pygame.K_LEFT:
player.izquierda()
if event.key == pygame.K_x:
player.stop()
if event.key == pygame.K_UP:
canjump = True
player.ha_saltado = True
gravity control
if canjump == True and player.ha_saltado == True:
player.salto()
else:
player.ha_saltado = False
if player.y < 550:
player.y += 10
level control(when the player x coordinate is greater than the screen width, the level increases)
if player.x >= width:
level += 1
player.x = 100
if level == 1:
texto.write("welcome to monochromatic adventure", 43, 200)
if level == 3:
plataforma.dibujar(800,500)
player.colisiones()
if level == 2:
texto.write("stage 1: Anguish", 43, 200)
update the game frames and draw the objects
#dibujar escenario
player.dibujar()
pygame.draw.line(screen, white, [1000, 600], [0, 600], 2)
reloj.tick(60)
pygame.display.flip()

There is a bug in the dibujar method. It must be self.rect.x = self.x instead of self.rect.x = self.x + self.change_x:
class Player:
# [...]
def dibujar(self):
self.x += self.change_x
self.rect.x = self.x
self.rect.y = self.y
screen.blit(self.image, self.rect)

Related

Im stuck in my pygame project, i dont know how to add sprites, scroll, and animated backgrounds

Context: Im trying to add something and i dont know, scroll, animated background and sprites.
And with the sound im confuse, other thing is that i dont know how to add time to my game, like for example a counter, or to add some time between an action in the game, i had working in this my project since last week, and stay stuck at this point, i search on google or anywhere and doesnt find what i want.
import pygame
import random
from pygame.locals import *
import pickle
from os import path
from pygame import mixer
import time
pygame.mixer.pre_init(44100, -16, 2, 512)
pygame.init()
mixer.init()
clock = pygame.time.Clock()
fps = 60
ancho = 1000
alto = 1000
bg = pygame.image.load("img/Background/inicio.jpg")
segu = pygame.image.load("img/Iconos/juega.png")
salgan = pygame.image.load("img/Iconos/quit.png")
jugador = pygame.image.load(f"img/player/Idle/0.png")
pantalla = pygame.display.set_mode((ancho, alto))
icon = pygame.display.set_caption("You")
opciones = pygame.image.load("img/Iconos/pauson.png")
resumen = pygame.image.load("img/Iconos/restart.png")
pygame.mixer.music.load("snd/feel.wav")
pygame.mixer.music.set_volume(0.1)
coin_fx = pygame.mixer.Sound("snd/coins.wav")
coin_fx.set_volume(0.5)
flip = pygame.mixer.Sound("snd/flip.wav")
# define font
font = pygame.font.SysFont("freesansbold", 104)
font_score = pygame.font.SysFont("freesansbold", 30)
# variables
money = 0
pressed = False
mantener = False
scroll = 0
pausa = False
pablo = False
def draw_text(text, font, text_col, x, y):
img = font.render(text, True, text_col)
pantalla.blit(img, (x, y))
class Button():
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.clicked = False
def draw(self):
action = False
# get mouse position
pos = pygame.mouse.get_pos()
# check mouseover and clicked conditions
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
action = True
self.clicked = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
# draw button
pantalla.blit(self.image, self.rect)
# pygame.draw.rect(pantalla, (255, 255, 255), self.rect, 2)
return action
class Pausa:
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def draw(self):
pantalla.blit(self.image, self.rect)
class Player:
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self): # update se utiliza para la posicion del jugador y su movilidad
dx = 0
dy = 0
key = pygame.key.get_pressed()
if key[pygame.K_a]:
dx -= 5
self.direction = -1
if key[pygame.K_d]:
dx += 5
self.direction = 1
if key[pygame.K_w]:
dy -= 5
if key[pygame.K_s]:
dy += 5
if key[pygame.K_z]:
pygame.mixer.music.play(-1, 0.0, 5000)
draw_text("Tienes " + str(money) + " monedas", font_score, (0, 0, 0), 800, 10)
# update player coordinates
self.rect.x += dx
self.rect.y += dy
def draw(self):
pantalla.blit(self.image, self.rect)
class Player2:
def __init__(self, x, y, image):
self.image = image
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self): # update se utiliza para la posicion del jugador y su movilidad
dx = 0
dy = 0
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
dx -= 5
self.direction = -1
if key[pygame.K_RIGHT]:
dx += 5
self.direction = 1
if key[pygame.K_UP]:
dy -= 5
if key[pygame.K_DOWN]:
dy += 5
if key[pygame.K_z]:
pygame.mixer.music.play(-1, 0.0, 5000)
draw_text("Tienes " + str(money) + " monedas", font_score, (0, 0, 0), 800, 10)
# update rectangle position
self.rect.x += dx
self.rect.y += dy
def draw(self):
pantalla.blit(self.image, self.rect)
jugador1 = Player(500, 500, jugador)
jugador2 = Player2(0, 0, jugador)
seguro = Button(500, 500, segu)
pausaoff = Pausa(0,0, opciones)
salir = Button(20, 420, salgan)
continuar = Button(20, 20, segu)
returno = Button(20, 300, resumen)
run = True
while run:
clock.tick(fps)
pantalla.blit(bg, (0, 0))
if pablo == True:
if seguro.draw():
pass
mantener = True
pygame.mixer.music.play(-1, 0.0, 5000)
if mantener == True:
Player.draw(jugador1)
Player.update(jugador1)
Player2.draw(jugador2)
Player2.update(jugador2)
pablo = False
if pausa == True:
pausaoff.draw()
mantener = False
if salir.draw():
flip.play()
pass
if returno.draw():
flip.play()
mantener = True
pausa = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_v:
money += 1
if money >= 10:
if event.key == pygame.K_x:
money -= 10
if event.key == pygame.K_r:
pausa = True
flip.play()
if event.key == pygame.K_ESCAPE:
pausa = False
if event.key == pygame.K_b:
pablo = True
if event.key == pygame.K_ESCAPE:
pablo = False
if event.type == pygame.KEYUP:
pass
pygame.display.update()
pygame.quit()
I can help you with sprites, but scrolling and animated backgrounds are way out of my league. So I see you have loaded the images, and assuming you have no error images, in the while run loop, simply type this:
pantalla.blit(sprite loading variable,(spriteX,SpriteY))
pantalla is your screen, pantalla.blit() is needed to "blit" or put one image on top of another, sprite loading variable is something like jagudor because you wrote pygame.image.load(), then SpriteX and SpriteY are the x and y coordinates of the image. I recommend you start reading some pygame books because blitting an image is like the first thing you learn in pygame.

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

player's Rect is not aligned with the player/character

I got the bullets to shoot but the player rect is not aligned with the player itself, so the bullets doesn't come from the player but rather from the rect that is offset.
The 3 main Classes:
(bullet, camera and player)
def RelRect(char, camera):
return Rect(char.rect.x - camera.rect.x, char.rect.y - camera.rect.y, char.rect.w, char.rect.h)
class Camera(object):
'''Class for center screen on the player'''
def __init__(self, screen, player, levelWidth, levelHeight):
self.player = player
self.rect = screen.get_rect()
self.rect.center = self.player.center
self.worldRect = Rect(0, 0, levelWidth, levelHeight)
def update(self):
if self.player.centerx > self.rect.centerx:
self.rect.centerx = self.player.centerx
if self.player.centerx < self.rect.centerx:
self.rect.centerx = self.player.centerx
if self.player.centery > self.rect.centery:
self.rect.centery = self.player.centery
if self.player.centery < self.rect.centery:
self.rect.centery = self.player.centery
def draw_sprites(self, surface, sprites):
for sprite in sprites:
if sprite.rect.colliderect(self.rect):
surface.blit(sprite.image, RelRect(sprite, self))
class Bullet():
def __init__(self, x, y, targetX, targetY):
self.image = ''
self.origX = x
self.origY = y
self.x = x
self.y = y
self.targetX = targetX
self.targetY = targetY
self.image = image.load('res/attack/attack.png')
self.vel = 20
# rnge is the range of the bullet, in frames
self.rnge = 50
# prog is the progress of the bullet, in frames
self.prog = 0
# dmg is the damage that the bullet will do upon impact
self.dmg = 1
self.dmg_mult = 1
# deathtick is the timer for enemy death
self.deathTick = 0
# rect is the hitbox of the bullet
self.w, self.h = self.image.get_width(), self.image.get_height()
self.rect = Rect(self.x, self.y, self.w, self.h)
def update(self):
# Increases Progress of the bullet
if not (sqrt((self.targetX - self.origX) ** 2 + (self.targetY - self.origY) ** 2)) == 0:
self.x += int((self.vel) * (self.targetX - self.origX) /
(sqrt((self.targetX - self.origX) ** 2 +
(self.targetY - self.origY) ** 2)))
self.y += int((self.vel) * (self.targetY - self.origY) /
(sqrt((self.targetX - self.origX) ** 2 +
(self.targetY - self.origY) ** 2)))
self.rect.center = [self.x, self.y]
def check(self, enemies):
# Checks if the bullet is out of range, then deletes it, if it is
if self.prog >= self.rnge:
bullets.remove(self)
#checks if bullets are out of bounds
elif not 0 < self.x < WIDTH - self.w or not 0 < self.y < HEIGHT - self.h:
bullets.remove(self)
else:
#checks if bullet hits target hitbox, if so, starts a timer that kills the bullet after 1 frame
for e in enemies:
if self.rect.colliderect(e.hitbox):
self.deathTick += 1
if self.deathTick > 1:
bullets.remove(self)
#draws each bullet
def draw(self):
screen.blit(self.image, self.rect)
#draws bullet hitboxes
def debug(self):
draw.rect(screen, (0,0,0), self.rect, 2)
draw.line(screen, (255,255,255), (self.x, self.y), (self.targetX, self.targetY), 4)
class Player(sprite.Sprite):
'''class for player and collision'''
def __init__(self, x, y):
sprite.Sprite.__init__(self)
self.moveUnitsY = 0
self.moveUnitsX = 0
self.x = x
self.y = y
self.ground = False
self.jump = False
self.image = image.load("res/move/Ridle.png").convert()
self.rect = self.image.get_rect()
self.Lrun = ["res/move/L1.png",
"res/move/L2.png",
"res/move/L3.png",
"res/move/L4.png",
"res/move/L5.png",
"res/move/L6.png"]
self.Rrun = ["res/move/R1.png",
"res/move/R2.png",
"res/move/R3.png",
"res/move/R4.png",
"res/move/R5.png",
"res/move/R6.png"]
self.direction = "right"
self.rect.topleft = [x, y]
self.frame = 0
def update(self, up, down, left, right):
if up:
if self.ground:
if self.direction == "right":
self.image = image.load("res/move/Ridle.png")
self.jump = True
self.moveUnitsY -= 20
if down:
if self.ground and self.direction == "right":
self.image = image.load("res/move/Ridle.png").convert_alpha()
if self.ground and self.direction == "left":
self.image = image.load("res/move/Lidle.png").convert_alpha()
if not down and self.direction == "right":
self.image = image.load("res/move/Ridle.png").convert_alpha()
if not down and self.direction == "left":
self.image = image.load("res/move/Lidle.png").convert_alpha()
if left:
self.direction = "left"
self.moveUnitsX = -vel
if self.ground:
self.frame += 1
self.image = image.load(self.Lrun[self.frame]).convert_alpha()
if self.frame == 4: self.frame = 0
else:
self.image = self.image = image.load("res/move/Lidle.png").convert_alpha()
if right:
self.direction = "right"
self.moveUnitsX = +vel
if self.ground:
self.frame += 1
self.image = image.load(self.Rrun[self.frame]).convert_alpha()
if self.frame == 4: self.frame = 0
else:
self.image = self.image = image.load("res/move/Ridle.png").convert_alpha()
if not (left or right):
self.moveUnitsX = 0
self.rect.right += self.moveUnitsX
self.collide(self.moveUnitsX, 0, world)
if not self.ground:
self.moveUnitsY += 0.3
if self.moveUnitsY > 10:
self.moveUnitsY = 10
self.rect.top += self.moveUnitsY
if self.jump:
self.moveUnitsY += 2
self.rect.top += self.moveUnitsY
if self.ground == True:
self.jump = False
self.ground = False
self.collide(0, self.moveUnitsY, world)
def collide(self, moveUnitsX, moveUnitsY, world):
self.ground = False
for pos in world:
if self.rect.colliderect(pos):
if moveUnitsX > 0:
self.rect.right = pos.rect.left
if moveUnitsX < 0:
self.rect.left = pos.rect.right
if moveUnitsY > 0:
self.rect.bottom = pos.rect.top
self.moveUnitsY = 0
self.ground = True
if moveUnitsY < 0:
self.rect.top = pos.rect.bottom
self.moveUnitsY = 0
and then the running loop:
while running:
for evnt in event.get():
if evnt.type == QUIT or evnt.type == KEYDOWN and evnt.key == K_ESCAPE:
running = False
if evnt.type == KEYDOWN and evnt.key == K_UP:
up = True
if evnt.type == KEYDOWN and evnt.key == K_DOWN:
down = True
if evnt.type == KEYDOWN and evnt.key == K_LEFT:
left = True
if evnt.type == KEYDOWN and evnt.key == K_RIGHT:
right = True
if evnt .type == MOUSEBUTTONDOWN:
# checks if any mouse button is down, if so sets clicking to true
button = evnt.button
#startTicks = time.get_ticks()
if evnt.type == MOUSEBUTTONUP:
# checks if any mouse button is down, if so sets clicking to true
button = 0
if evnt.type == MOUSEMOTION:
# sets mx and my to mouse x backgand y if mouse is moving
mx, my = evnt.pos
if evnt.type == KEYUP and evnt.key == K_UP:
up = False
if evnt.type == KEYUP and evnt.key == K_DOWN:
down = False
if evnt.type == KEYUP and evnt.key == K_LEFT:
left = False
if evnt.type == KEYUP and evnt.key == K_RIGHT:
right = False
if button == 1:
bullets.append(Bullet(player.rect[0]+ player.rect[2]//2, player.rect[1] + player.rect[3]//2, mx, my))
asize = ((screen_rect.w // background_rect.w + 1) * background_rect.w, (screen_rect.h // background_rect.h + 1) * background_rect.h)
bg = Surface(asize)
for x in range(0, asize[0], background_rect.w):
for y in range(0, asize[1], background_rect.h):
screen.blit(background, (x, y))
for b in bullets:
b.update()
b.draw()
b.check(enemies)
time_spent = sec(clock, FPS)
camera.draw_sprites(screen, all_sprite)
draw.rect(screen, (255,0,0), player.rect, 4)
player.update(up, down, left, right)
camera.update()
display.flip()
if you run the program itself, you can see that the red rectangle (4th last line) that represents the player rect is not to where the character is suppose to appear....
How can I make it so that the player rect will be at the position of the character? So that the bullets come from the player.
Thanks :)
Full Code Here:
https://pastebin.com/z1LwxYYt
The problem with your code is that neither your red rectangle nor the bullets are drawn to the screen in relation to the camera.
The Bullet class should subclass Sprite, too, so you can add them to the all_sprite-group, like you do with the obstacles and the player.
Then let the Camera-class handle the drawing of the bullets.
As for the red rectangle, I suggest removing the RelRect function and move it into the Camera class itself, like this:
class Camera(object):
...
def translate(self, rect):
return Rect(rect.x - self.rect.x, rect.y - self.rect.y, rect.w, rect.h)
def draw_sprites(self, surface, sprites):
for sprite in sprites:
if sprite.rect.colliderect(self.rect):
surface.blit(sprite.image, self.translate(sprite.rect, self))
which would allow you to draw the rect like this:
draw.rect(screen, (255,0,0), camera.translate(player.rect), 4)

how to target a sprite randomly

I am trying to create a retro style 2d shooter game and am currently making a homing missile. I need to randomly select a sprite from a group (pygame.sprite.Group) and find out its x and y coords. I have already made it home in on these coords so I do not need help with that. My code is:
an Enemy class (they are all the same just with different sizes and pictures):
class EnemyShipLevel1(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("C:/Users /Me/PycharmProjects/Game folder/SpaceShip game/Enemy1.png")
self.rect = self.image.get_rect()
self.rect.y = -50
self.rect.centerx = random.randint(15, SCREEN_WIDTH-15)
self.change_y = 0
self.cooldown = 0
self.targetx = 500
self.health = 1
if self.targetx >= self.rect.centerx:
self.change_x = 2
else:
self.change_x = -2
def update(self):
self.rect.x += self.change_x
self.rect.y += self.change_y
if self.rect.centery < 200:
self.rect.centery += 2
self.get_target()
if self.targetx > self.rect.centerx+10:
self.change_x = 3
elif self.targetx < self.rect.centerx-10:
self.change_x = -3
else:
self.change_x = 0
self.cooldown -= 1
if self.rect.left < screen_rect.left:
self.change_x = -self.change_x
if self.rect.right > screen_rect.right:
self.change_x = -self.change_x
if self.cooldown < 0 and (self.rect.centerx-50 < self.targetx < self.rect.centerx+50) and player.trans is False:
self.cooldown = random.randint(15, 25)
laser = NormalLaser(self.rect.centery, self.rect.centerx, False, 0, 8)
all_sprite_list.add(laser)
enemy_laser_list.add(laser)
player_laser_hit_list = pygame.sprite.spritecollide(self, player_laser_list, True)
for laser in player_laser_hit_list:
if self.health < 1:
all_sprite_list.remove(self)
enemy_list.remove(self)
else:
self.health -= 1
def get_target(self):
self.targetx = player.rect.centerx
Targeting Laser class (I know you can't bend lasers):
class TargetingLaser(pygame.sprite.Sprite):
def __init__(self, start_x, start_y, dest_x, dest_y):
super().__init__()
self.floating_point_x = start_x
self.floating_point_y = start_y
self.x_diff = dest_x - start_x
self.y_diff = dest_y - start_y
self.angle = math.atan2(self.y_diff, self.x_diff)
self.velocity = 10
self.change_x = math.cos(self.angle) * self.velocity
self.change_y = math.sin(self.angle) * self.velocity
self.image = pygame.image.load("C:/Users/Minecraft/PycharmProjects/Game folder/SpaceShip game/Laser.png")
self.image = pygame.transform.rotate(self.image, -(math.degrees(self.angle)+90))
self.rect = self.image.get_rect()
self.rect.centerx = start_x
self.rect.centery = start_y
def update(self):
self.floating_point_y += self.change_y
self.floating_point_x += self.change_x
self.rect.y = int(self.floating_point_y)
self.rect.x = int(self.floating_point_x)
if self.rect.top < screen_rect.top:
player_laser_list.remove(self)
enemy_laser_list.remove(self)
all_sprite_list.remove(self)
if self.rect.bottom > screen_rect.bottom:
player_laser_list.remove(self)
all_sprite_list.remove(self)
enemy_laser_list.remove(self)
if self.rect.left < screen_rect.left:
player_laser_list.remove(self)
all_sprite_list.remove(self)
enemy_laser_list.remove(self)
if self.rect.right > screen_rect.right:
player_laser_list.remove(self)
all_sprite_list.remove(self)
enemy_laser_list.remove(self)
Game Loop:
all_sprite_list = pygame.sprite.Group()
enemy_list = pygame.sprite.Group()
player_list = pygame.sprite.GroupSingle()
player_laser_list = pygame.sprite.Group()
enemy_laser_list = pygame.sprite.Group()
live_list = pygame.sprite.Group()
health_bar_list = pygame.sprite.GroupSingle()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
screen_rect = screen.get_rect()
pygame.display.set_caption('Game')
clock = pygame.time.Clock()
Play = True
player = Player(SCREEN_WIDTH/2, SCREEN_HEIGHT-30)
all_sprite_list.add(player)
player_list.add(player)
for counter in range(2):
enemy = EnemyShipLevel1()
all_sprite_list.add(enemy)
enemy_list.add(enemy)
live1 = LivesIcon(5, 0, 1)
live_list.add(live1)
live1 = LivesIcon(27, 30, 2)
live_list.add(live1)
live1 = LivesIcon(50, 0, 3)
live_list.add(live1)
live1 = LivesIcon(72, 30, 4)
live_list.add(live1)
live1 = LivesIcon(95, 0, 5)
live_list.add(live1)
all_sprite_list.add(live_list)
health_bar = PlayerHealthBar(0, 690)
all_sprite_list.add(health_bar)
health_bar_list.add(health_bar)
ship = EnemyShipLevel3()
all_sprite_list.add(ship)
enemy_list.add(ship)
while Play is True:
# Shooting
if player.shooting is True:
if player.laser_cooldown < 0:
player.laser_cooldown = 5
if player.last_shot == "left":
player.last_shot = "right"
laser = NormalLaser(player.rect.centery-2, player.rect.centerx + 11, True, 0, 8)
all_sprite_list.add(laser)
player_laser_list.add(laser)
else:
player.last_shot = "left"
laser = NormalLaser(player.rect.centery-2, player.rect.centerx - 11, True, 0, 8)
all_sprite_list.add(laser)
player_laser_list.add(laser)
if player.rocket_cooldown < 0:
player.rocket_cooldown = 15
for counter in range(10):
laser = TargetingLaser(player.rect.centerx,player.rect.centery, player.rect.centerx, 0)
all_sprite_list.add(laser)
player_laser_list.add(laser)
# Shooting
# Levels
if len(enemy_list) == 0:
all_sprite_list.remove(enemy_laser_list)
all_sprite_list.remove(player_laser_list)
enemy_laser_list.empty()
player_laser_list.empty()
player.level += 1
for counter in range(player.spawn_enemies1):
enemy = EnemyShipLevel1()
all_sprite_list.add(enemy)
enemy_list.add(enemy)
for counter in range(player.spawn_enemies2):
enemy2 = EnemyShipLevel2()
all_sprite_list.add(enemy2)
enemy_list.add(enemy2)
for counter in range(player.spawn_enemies3):
ship = EnemyShipLevel3()
all_sprite_list.add(ship)
enemy_list.add(ship)
if player.level == 2:
player.spawn_enemies1 = 3
player.spawn_enemies2 = 1
if player.level == 3:
player.spawn_enemies1 = 5
player.spawn_enemies2 = 2
if player.level == 4:
player.spawn_enemies1 = 10
player.spawn_enemies2 = 5
if player.level == 5:
player.spawn_enemies1 = 12
player.spawn_enemies2 = 8
player.spawn_enemies3 = 1
# Levels
# End Game
if player.lives == 0:
Play = False
# End Game
# Keys
for event in pygame.event.get():
if event.type == pygame.QUIT:
Play = False
elif event.type == pygame.KEYDOWN:
if (event.key == pygame.K_a) or (event.key == pygame.K_LEFT):
player.change_x = -5
elif (event.key == pygame.K_d) or (event.key == pygame.K_RIGHT):
player.change_x = 5
if event.key == pygame.K_SPACE:
player.shooting = True
elif event.type == pygame.KEYUP:
player.rotation = 0
player.change_x = 0
player.change_y = 0
if event.key == pygame.K_SPACE:
player.shooting = False
# Keys
all_sprite_list.update()
screen.fill(BLACK)
all_sprite_list.draw(screen)
enemy_laser_list.draw(screen)
player_laser_list.draw(screen)
pygame.display.update()
clock.tick(60)
quit()
Each time you kill all of the spawned enemies then the game spawns in more and adds them to enemy_list().
If you are asking how to randomly choose a sprite then use a random.randint(0, 30) (or the number of sprites) then do a long series of if statements. Example Code.
import random
import pygame
class Enemy:
def __init__()
random_sprite = random.randint(0, 1)
# Then put in two variables which equal to the png (I will use sprite1 and sprite2)
def sprite_render
if random_sprite == 0:
# Just blit sprite1
elif random_sprite == 1:
# Just blit sprite2
(The reason why I just commented the actions for the image stuff is because almost everyone does it in a different way and that is not the main point of this answer.)
You could assign a number attribute to each enemy.
For example, you could start off your enemy function like this:
class EnemyShipLevel1(pygame.sprite.Sprite):
number = None
def __init__(self,number):
super().__init__()
self.number = number
self.image = pygame.image.load("C:/Users /Me/PycharmProjects/Game folder/SpaceShip game/Enemy1.png")
Now when you spawn in the enemies, you would add the number attribute:
for counter in range(2): # change this number to use more than 2 enemies (I use 30 later)
enemy = EnemyShipLevel1(counter)
all_sprite_list.add(enemy)
enemy_list.add(enemy)
All you have to do is randomly choose the sprite:
choice = random.randrange(0,30) # between 0 and the number of enemies spawned
for i in enemy_list:
if i.number == choice:
# make i the target of the laser
target_x = i.rect.x
target_y = i.rect.y

Pygame - Collisions With Floor/Walls

Hello I am currently making a survival shooter but cannot find any way on how to do my collisions! I am trying to make the player collide with the floors but with no success. Here is an image of the map (I want to collide with moon blocks):
http://i.stack.imgur.com/R2apz.jpg
Here is an image of moon blocks with no Background:
http://i.stack.imgur.com/W9H2m.png
And finally here is my code:
import pygame
import random
gravity = .5
jump_time = 2000
x = 0
y = 0
# Player
class Player(pygame.sprite.Sprite):
def __init__(self, x, y, gravity):
# Player dimensions and position
self.gravity = gravity
# Player image and animation
self.images = []
self.images.append(pygame.image.load('images/player.png'))
self.images.append(pygame.image.load('images/player2.png'))
#~ self.images.append(pygame.image.load('ball1.png'))
#~ self.images.append(pygame.image.load('ball2.png'))
self.maxImage = len(self.images)
self.currentImage = 0
#~ self.rect = pygame.Rect(x, y, 80, 80)
self.rect = self.images[0].get_rect()
self.rect.x = x
self.rect.y = y
self.timeTarget = 10
self.timeNum = 1
self.velX = 0
self.velY = 0
# Jump and gravity
self.vSpeed = 3
self.jumpForce = 15
self.maxVspeed = 3
self.isJumping = False
# Jump inputs
def handle_events(self, event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if not self.isJumping:
self.isJumping = True
elif event.key == pygame.K_a:
self.velX = -5
elif event.key == pygame.K_d:
self.velX = +5
elif event.type == pygame.KEYUP:
if event.key in (pygame.K_a, pygame.K_d):
self.velX = 0
# PLayer updates
def update(self, ground):
keys = pygame.key.get_pressed()
# Jumping
self.vSpeed += gravity
if self.vSpeed > self.maxVspeed:
self.vSpeed = self.maxVspeed
self.rect.y += self.vSpeed
if self.rect.y >= ground.y:
self.vSpeed = 0
self.rect.y = ground.y
self.isJumping = False
if keys[pygame.K_SPACE]:
if not self.isJumping:
self.isJumping = True
if self.isJumping:
if pygame.time.get_ticks() < jump_time:
self.isJumping == True
else:
self.isJumping = False
self.vSpeed -= self.jumpForce
#print "isJumping:", self.isJumping
# Animations
if self.timeNum == self.timeTarget:
self.currentImage += 1
if self.currentImage >= self.maxImage:
self.currentImage = 0
self.timeNum = 0
self.rect.centerx += self.velX
self.rect.centery += self.velY
# Screen wrap
if self.rect.right > 1280:
self.rect.left = 0
elif self.rect.left < 0:
self.rect.right = 1280
# Player rendering
def render(self, surface):
surface.blit(self.images[self.currentImage], self.rect)
#----------------------------------------------------------------------
class Zombie():
def __init__(self, x, y):
self.image = pygame.image.load('images/zombie.png')
#~ self.image = pygame.image.load('ball2.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.direction_left = True
def update(self, surface_rect):
if self.direction_left:
self.rect.x -= 1
if self.rect.left <= surface_rect.left:
self.direction_left = not self.direction_left
else:
self.rect.x += 1
if self.rect.right >= surface_rect.right:
self.direction_left = not self.direction_left
def render(self, surface):
surface.blit(self.image, self.rect)
#----------------------------------------------------------------------
class Background():
def __init__(self):
self.image = pygame.image.load('images/arena2.jpg')
#~ self.image = pygame.image.load('background.jpg')
self.rect = self.image.get_rect()
def render(self, surface):
surface.blit(self.image, self.rect)
#----------------------------------------------------------------------
class Game():
def __init__(self):
pygame.init()
# A few variables
self.gravity = .50
self.ground = pygame.Rect(0, 640, 1280, 80)
# Screen
size = (1280, 720)
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption('Moon Survival!')
# Moon / Background
self.moon = Background()
# Zombies
self.zombies = []
for i in range(10):
self.zombies.append( Zombie(random.randint(0,1280), random.randint(0,720)) )
# Player
self.player = Player(25, 320, self.gravity)
# Font for text
self.font = pygame.font.SysFont(None, 72)
# Pause - center on screen
self.pause_text = self.font.render("PAUSE", -1, (255,0,0))
self.pause_rect = self.pause_text.get_rect(center = self.screen.get_rect().center)
def run(self):
clock = pygame.time.Clock()
# "state machine"
RUNNING = True
PAUSED = False
GAME_OVER = False
# Game loop
while RUNNING:
# (all) Events
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
RUNNING = False
elif event.key == pygame.K_p:
PAUSED = not PAUSED
# Player/Zomies events
if not PAUSED and not GAME_OVER:
self.player.handle_events(event)
# (all) Movements / Updates
if not PAUSED and not GAME_OVER:
self.player.update(self.ground)
for z in self.zombies:
z.update(self.screen.get_rect())
# (all) Display updating
self.moon.render(self.screen)
for z in self.zombies:
z.render(self.screen)
self.player.render(self.screen)
if PAUSED:
self.screen.blit(self.pause_text, self.pause_rect)
pygame.display.update()
# FTP
clock.tick(100)
# --- the end ---
pygame.quit()
#---------------------------------------------------------------------
Game().run()
Any help will be greatly appreciated, thank you.
I made a very similar game for PyWeek #17 called "Miner".
Here's a screenshot: http://media.pyweek.org/dl/17/powrtoch/miner_ss.png (you can see the similarity!)
You can find the relevant code on GitHub here: https://github.com/marcusmoller/pyweek17-miner/blob/master/miner/engine.py#L202-L220:
def checkCollision(self, sprite, xVel, yVel):
for x in range(len(level.levelStructure)):
for y in range(len(level.levelStructure[x])):
block = level.levelStructure[x][y]
if block is not None:
if pygame.sprite.collide_rect(sprite, block):
if xVel < 0:
sprite.rect.x = block.rect.x + block.rect.w
if xVel > 0:
sprite.rect.x = block.rect.x - sprite.rect.w
if yVel < 0:
sprite.rect.y = block.rect.y + block.rect.h
if yVel > 0 and not sprite.onGround:
sprite.onGround = True
sprite.rect.y = block.rect.y - sprite.rect.h
You could do something like this using collide_rect:
# See if the Sprite block collides with anything in the Ground block_list
for block in groundBlocks:
if(collide_rect(player, block)):
# do not fall
else:
# fall
where all Block you can walk on are in the groundBlocks list.

Categories

Resources