Making sprites inside/outside of a class - python

I've got all my code working on its own. I need to start linking it all to buttons though.
QUESTION: trying to setup multiple buttons as sprites for collision purposes. Don't know how to do it outside of a class.
I have buttons working in seperate classes, but cannot get them to work in the same class for the obvious reason of, the self.image of the second one is overwriting the first one.
class Icons(pygame.sprite.Sprite):
def __init__(self, *args):
pygame.sprite.Sprite.__init__(self, *args)
self.image = pygame.image.load("images/airbrushIC.gif").convert()
self.rect = self.image.get_rect()
ic1 = self.image
self.rect.x = 50
self.rect.y = 490
self.image = pygame.image.load("images/fillIC.gif").convert()
self.rect = self.image.get_rect()
ic2 = self.image
self.rect.x = 10
self.rect.y = 540
def update(self):
pygame.mouse.get_pos()
pygame.mouse.get_pressed()
This code doesn't have to be a class. But I do not know how to make the images a sprite without being inside of a class. Any help would be appriciated thanks!

Instead of Icons you should have a generic Icon class.
Then you can create an instance of Icon for each button.
class Icon(pygame.sprite.Sprite):
def __init__(self, image_name, pos, cb, cb_data, *args):
pygame.sprite.Sprite.__init__(self, *args)
self.image = pygame.image.load("images/" + image_name).convert()
self.rect = self.image.get_rect()
self.rect.x = pos[0]
self.rect.y = pos[1]
this.cb = cb # function to call when button is pressed
this.cb_data = cb_data # data to pass to the function
def pressed():
this.cb(cb_data)
Then in you main function you create the buttons:
ic1 = Icon("airbrushIC.gif", (50, 490), button_pressed, "airbrushIC")
ic2 = Icon("fillIC.gif", (10, 540), button_pressed, "fillIC")
buttons = [ic1, ic2]
def button_pressed(data):
print "Button pressed:" + str(data)
Last, for every mouse down event you look for a button collition:
for b in buttons:
if b.rect.collidepoint(event.pos):
b.pressed()

Related

Pygame: update in the while loop not succesful

A helicopter is shot at. If he is hit, he falls. At the same time, a parachute releases from the helicopter. If the parachute is shot at and also hit by a bullet, the image of the parachute should be replaced with another image.
The jump with the parachute is done by the function absprung. The parachute is created with the Fallschirm class. The shelling is queried via collide.
It doesn't work, the picture is not changed.
def absprung(self): #Auslöser Fallschirm
fallschirm = Fallschirm(self.rect.centerx, self.rect.top)
alle_sprites.add(fallschirm)
fallschirme.add(fallschirm)
class Fallschirm(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Bilder/fallschirm.png").convert_alpha()
self.image = pygame.transform.scale(self.image,(100,150))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.beschuss = False
def update(self):
if self.beschuss == True:
self.image = pygame.image.load("Bilder/fadenkreuz.png").convert_alpha()
self.image = pygame.transform.scale(self.image,(100,150))
self.rect.y +=2
if self.rect.y > hoehe:
self.kill()
hits = pygame.sprite.groupcollide(fallschirme,bullets,False,True)
for hit in hits:
fallschirme.beschuss = True
beschuss is an attribute of a single Falschirm object, but not an attribute of fallschirme. pygame.sprite.groupcollide returns a dictionary of objects that were hit. You must set the attribute to these objects.
hits = pygame.sprite.groupcollide(fallschirme, bullets,False,True)
for fallschirm in hits:
fallschirm.beschuss = True

Transparency in pygame sprites

I can't figure out why the code below renders the sprite without transparency (with the rest of the sprite filled with black). I'm almost a beginner to programming so it might be very obvious but no other answers to similar questions here helped me. The file has transparency and I used convert_alpha() when loading the file.
import pygame
class Piece(pygame.sprite.Sprite):
def __init__(self, kind, posx, posy, sheet, color):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image for the piece and fill it with the image
# TO DO: cut the right type of piece from a sheet, preferably before constructing the object
self.image = pygame.Surface([128, 128])
self.image.blit(sheet, [0, 0])
self.kind = kind # piece type, designated with an uppercase letter, eg. Q for queen
self.color = color # W or B for white or black
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
self.rect.x = posx
self.rect.y = posy
class App:
def __init__(self):
self._running = True
self._display_surf = None
self.size = self.weight, self.height = 1024, 768
self.sprites = pygame.sprite.Group() # all sprites in the app to iterate on
self.spritesheet = 0 # this will be loaded later
self.bgcolor = [200, 200, 200]
def on_init(self):
pygame.init()
self._display_surf = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
self._running = True
self.spritesheet = pygame.image.load("resources/w_queen_png_shadow_128px.png", "r").convert_alpha()
self.sprites.add(Piece("Q", 64, 64, self.spritesheet, "W"))
def on_event(self, event):
if event.type == pygame.QUIT:
self._running = False
def on_loop(self):
pass
def on_render(self):
self._display_surf.fill(self.bgcolor)
self.sprites.draw(self._display_surf)
pygame.display.flip()
def on_cleanup(self):
pygame.quit()
def on_execute(self):
if self.on_init() is False:
self._running = False
while self._running:
for event in pygame.event.get():
self.on_event(event)
self.on_loop()
self.on_render()
self.on_cleanup()
if __name__ == "__main__":
game = App()
game.on_execute()
If you are copying an image with a per pixel alpha format on another pygame.Surface onto another surface, you need to ensure that the target Surface has a per pixel alpha format, too. If the target cannot save the alpha channel, the transparency will be lost. Set the SRCALPHA flag to create a surface with an image format that includes a per-pixel alpha.
self.image = pygame.Surface([128, 128])
self.image = pygame.Surface([128, 128], pygame.SRCALPHA)
class Piece:
class Piece(pygame.sprite.Sprite):
def __init__(self, kind, posx, posy, sheet, color):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image for the piece and fill it with the image
# TO DO: cut the right type of piece from a sheet, preferably before constructing the object
self.image = pygame.Surface([128, 128], pygame.SRCALPHA)
self.image.blit(sheet, [0, 0])
self.kind = kind # piece type, designated with an uppercase letter, eg. Q for queen
self.color = color # W or B for white or black
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
self.rect.x = posx
self.rect.y = posy

Pygame returning locking error during blitting

I am trying to make a 2D game in pygame, and have a camera class that has a surface attribute, and each time the cameras get updated their surface is updated. All graphics are blitted to game.worldSurface, and then the main camera take a picture of that and blits it to the display surface. However, when using other cameras, i am unable to blit to the worldsurface and get a locking error. i have tried .unlock(). what could be causing this?
import pygame
import pickle
class Tileset:
def __init__(self, location):
pass
class Tilemap:
def __init__(self):
pass
class Collisionmap(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
class Player(pygame.sprite.Sprite):
def __init__(self, spritesheet):
super().__init__()
self.spritesheet = pygame.image.load(spritesheet)
self.x = 0
self.y = 0
def draw(self, surface):
surface.blit(self.spritesheet, (self.x, self.y))
class Mob(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
class Camera:
def __init__(self):
self.x = 0
self.y = 0
self.width = 100
self.height = 100
self.surface = pygame.Surface((self.width, self.height))
def moveToSprite(self, sprite):
self.x = sprite.rect.centerx - WIDTH // 2
self.y = sprite.rect.centery - HEIGHT // 2
def update(self, world):
self.surface = world.subsurface((self.x, self.y, self.width, self.height))
class Level:
def __init__(self, terrarin, collision, mobs):
self.terrain = terrain
self.collision = collision
self.mobs = mobs
class Game:
def __init__(self):
pygame.init()
self.DISPLAYSURF = pygame.display.set_mode((0, 0))
self.mainCamera = Camera()
self.mainCamera.width = self.DISPLAYSURF.get_width()
self.mainCamera.height = self.DISPLAYSURF.get_height()
self.otherCameras = []
self.worldSurface = pygame.Surface((10000, 10000))
self.player = Player("marioSS.jpg")
self.otherCameras.append(Camera())
self.run()
def run(self):
while True:
for event in pygame.event.get():
pass
self.earlyUpdate()
self.update()
self.lateUpdate()
self.graphicsUpdate()
def update(self):
pass
def earlyUpdate(self):
pass
def lateUpdate(self):
pass
def graphicsUpdate(self):
for each in self.otherCameras:
each.update(self.worldSurface)
self.player.draw(self.worldSurface)
self.otherCameras[0].surface.unlock()
self.worldSurface.unlock()
self.worldSurface.blit(self.otherCameras[0].surface, (100, 100)) ##Error here
self.mainCamera.update(self.worldSurface)
self.DISPLAYSURF.blit(self.mainCamera.surface, (0, 0))
pygame.display.update()
x = Game()
Problem makes world.subsurface() in Camera.update()
It doesn't copy data from world to surface but it assigns access to original world. And later you have: camera.surface keeps access to world, and blit try to copy from camera.surface to world - so finally it tries to copy from world to world. And maybe it locks it.
But if in Camera.update() you use .copy()
self.surface = world.subsurface((self.x, self.y, self.width, self.height)).copy()
or blit it
self.surface.blit(world.subsurface((self.x, self.y, self.width, self.height)), (0,0))
then it works.
DOC: subsurface
subsurface(Rect) -> Surface
Returns a new Surface that shares its pixels with its new parent.

Problems with Sprites Appearing and Collision with Rotated Objects; Pygame object is not iterable

I'm currently trying to make pixel perfect collisions between my pong ball and my player's paddle using the mask and collide_rect functions. I made my own checkCollision function in the pong class which would check for pixel perfect collision. However, right now, I can't even get the Sprites to work or appear on the screen because my "Pong object is not iterable.
Here is my pong class with the important features: (I will post additional code if needed)
class Pong(pygame.sprite.Sprite):
def __init__(self, screensize):
pygame.sprite.Sprite.__init__(self)
self.screensize = screensize
self.centerx = screensize[0] // 2
self.centery = screensize[1] // 2
self.radius = 25
self.rect = pygame.Rect(self.centerx-self.radius,
self.centery-self.radius,
self.radius*2, self.radius*2)
self.pokeimage = pygame.image.load("pokeball.png")
self.pokeimage = pygame.transform.scale(self.pokeimage, (self.radius, self.radius))
#Create the mask
self.mask = pygame.mask.from_surface(self.pokeimage)
def checkCollision(self, player_paddle, ai_paddle):
col = pygame.sprite.collide_rect(self, player_paddle)
return col
def collisionFormula(self, player_paddle, ai_paddle):
if self.checkCollision(self, player_paddle):
def collision_checks(self, player_paddle, ai_paddle):
#if the ball hits the top or bottom of the screen, change the y direction
if self.rect.top <= 0 or self.rect.bottom >= self.screensize[1] - 1:
self.direction[1] *= -1
#if the pong hits the paddles, change how the pong ball moves
if self.rect.colliderect(player_paddle.rect) or self.rect.colliderect(ai_paddle.rect):
self.collisionFormula(player_paddle, ai_paddle)
def update(self, player_paddle, ai_paddle):
self.update_ball_position()
self.reset_ball()
self.collision_checks(player_paddle, ai_paddle)
In my PlayerPaddle class, I do the same mask initialization.
class PlayerPaddle(pygame.sprite.Sprite):
def __init__(self, screensize):
pygame.sprite.Sprite.__init__(self)
self.screensize = screensize
self.centerx = 50
self.centery = screensize[1]//2
self.height = 100
self.width = 20
self.imageMaster = pygame.image.load("naruto.png").convert_alpha()
self.imageMaster = pygame.transform.scale(self.imageMaster, (self.width, self.height))
self.image = self.imageMaster
#mask
self.mask = pygame.mask.from_surface(self.image)
def turnLeft(self):
self.dir += 45
if self.dir > 360:
self.dir = 45
def turnRight(self):
self.dir -= 45
if self.dir < 0:
self.dir = 315
def update(self):
#Rotate functions
oldCenter = self.rect.center
self.image = pygame.transform.rotate(self.imageMaster, self.dir)
self.rect = self.image.get_rect()
self.rect.center = oldCenter
And here is my main function:
def main():
pygame.init()
screensize = (640,700)
screen = pygame.display.set_mode(screensize)
background = pygame.Surface(screen.get_size())
background.fill((0, 255, 0))
clock = pygame.time.Clock()
pong = Pong(screensize)
player_paddle = PlayerPaddle(screensize)
ai_paddle = AIPaddle(screensize)
paddleSprite = pygame.sprite.Group(player_paddle)
pongSprite = pygame.sprite.Group(pong)
while running:
running = True
#object updating phase
ai_paddle.update(pong, player_paddle)
player_paddle.update()
pong.update(player_paddle, ai_paddle)
if pygame.sprite.spritecollide(player_paddle, pong, False, pygame.sprite.collide_mask):
print("Collided")
#rendering phase
ai_paddle.render(screen)
player_paddle.render(screen)
pong.render(screen)
paddleSprite.clear(screen, background)
paddleSprite.update()
paddleSprite.draw(screen)
pongSprite.clear(screen,background)
pongSprite.update()
pongSprite.draw(screen)
pygame.display.flip()
pygame.quit()
main()
I made two "group" objects (the pong and the player_paddle) but I'm not sure why I'm even failing to run the program. Additionally, I know the collision will not work because the pong ball will hit the rectangle of the original image, but not the rotated image, but I'm not sure why that will happen if I use the built in sprite function. Thanks.
Read documentation for spritecollide
Find sprites in a group that intersect another sprite.
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
Second argument has to be group (pygame.sprite.Group), not single Sprite.
It can be group event with one sprite. But you use pong which is single sprite, not group.
See documentation for collide_mask
Collision detection between two sprites, using masks.
collide_mask(SpriteLeft, SpriteRight) -> point
It checks collision between two sprites using mask.
EDIT: in your code you have problem with
spritecollide(player_paddle, pong,...)
because pong is single Sprite, not Group.
With pong you should use collide_mask
collide_mask(player_paddle, pong)
You can use spritecollidewith pongSprite which is Group
spritecollide(player_paddle, pongSprite,...)`
BTW: you could use better names ie. pong_group instead of pongSprite.
And eventually pong_sprite instead of pong (but pong is OK, too).

Pygame- Sprite set position with mouseclick

is there a possibilty to place a Sprite on the position, where i clicked?
class sprite_to_place(pygame.sprite.Sprite):
def __init__(self, x_start_position , y_start_position ):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("a_picture.png")
self.rect = self.image.get_rect()
self.rect.x = x_start_position # x where I clicked
self.rect.y = y_start_position # y where I clicked
When I initialize the sprite_to_place I would use pygame.mouse.get_pos().
And in the main loop I would place it with:
if event.type == pygame.MOUSEBUTTONDOWN:
sprite_to_place_group.draw(gameDisplay)
But how can I get the position of the sprite, if I want to change its position with def update()? (I use allsprites_group.update())
def update(self, startpos=(x_start_position, y_start_position)): # how can I tell the function where the sprite is on the map?
self.pos = [startpos[0], startpos[1]]
self.rect.x = round(self.pos[0] - cornerpoint[0], 0) #x
self.rect.y = round(self.pos[1] - cornerpoint[1], 0) #y
If I would do it like in my example, it says that x_start_position and y_start_position are not defined.
Thanks!
You store the current position of the Sprite already in self.rect, so you don't need x_start_position and y_start_position.
If you want to store the original starting position you used when creating the Sprite, you'll have to create a member in the initializer:
#TODO: respect naming convention
class sprite_to_place(pygame.sprite.Sprite):
# you can use a single parameter instead of two
def __init__(self, pos):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("a_picture.png")
# you can pass the position directly to get_rect to set it's position
self.rect = self.image.get_rect(topleft=pos)
# I don't know if you actually need this
self.start_pos = pos
Then in update:
def update(self):
# current position is self.rect.topleft
# starting position is self.start_pos
# to move the Sprite/Rect, you can also use the move functions
self.rect.move_ip(10, 20) # moves the Sprite 10px vertically and 20px horizontally

Categories