metalcruedude
metalcruedude

Reputation: 11

Python/Pygame sprites using same class not updating properly

import pygame, sys, random
pygame.init()

class Ship(pygame.sprite.Sprite):
    movepersec = 0
    dx = 0
    dy = 0
    direction = ""
    imgarray = {}

    def __init__(self, imgarr, rect, speed, xpos, ypos, direct):
        pygame.sprite.Sprite.__init__(self)

        self.imgarray = imgarr
        self.rect = rect
        self.movepersec = speed
        self.dx = xpos
        self.dy = ypos
        self.direction = direct
        self.image = self.imgarray[self.direction]

    def setDirection(self, direct):
            self.direction = direct

    def setSpeed(self, speed):
            self.movepersec = speed

    def update(self, secs):

        movePix = self.movepersec*secs

        if self.direction == "N": self.dy -= movePix
        if self.direction == "S": self.dy += movePix
        if self.direction == "E": self.dx += movePix
        if self.direction == "W": self.dx -= movePix

        self.rect.centerx = self.dx
        self.rect.centery = self.dy

        self.image = self.imgarray[self.direction]

background = pygame.image.load("sea.jpg")
backgroundWidth = background.get_width()
backgroundHeight = background.get_height()
size = background.get_size()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
imgarray = {}
imgarray["N"] = pygame.image.load("shipNorth.png")
imgarray["S"] = pygame.image.load("shipSouth.png")
imgarray["E"] = pygame.image.load("shipEast.png")
imgarray["W"] = pygame.image.load("shipWest.png")
imgrect = imgarray["N"].get_rect()
movepersec = 150
keydownflag = False
allSpriteGroup = pygame.sprite.Group()

shipX = Ship(imgarray, imgrect, movepersec, 100, 100, "E")
allSpriteGroup.add(shipX)

shipY = Ship(imgarray, imgrect, movepersec, 100, 100, "S")
allSpriteGroup.add(shipY)

screen.blit(background,(0,0))

while True:
    secs = clock.tick(30)/1000.0

    for event in pygame.event.get():
        if event.type == pygame.QUIT : sys.exit(0)

        if event.type == pygame.KEYDOWN:
            keydownflag = True

            if event.key == pygame.K_LEFT:
                shipX.setDirection("W")
            if event.key == pygame.K_RIGHT:
                shipX.setDirection("E")
            if event.key == pygame.K_UP:
                shipX.setDirection("N")
            if event.key == pygame.K_DOWN:
                shipX.setDirection("S")

        if event.type == pygame.KEYUP:
            keydownflag = False

    if keydownflag:
        shipX.update(secs)

    shipY.update(secs)

    #shipX collision
    if shipX.rect.right + 65 >= backgroundWidth:
        shipX.setDirection("W")
    if shipX.rect.bottom >= backgroundHeight:
        shipX.setDirection("N")
    if shipX.rect.left <= 0:
        shipX.setDirection("E")
    if shipX.rect.top <= 0:
        shipX.setDirection("S")

    #Ship Y collision
    if shipY.rect.top <= 0:
        shipY.setDirection("S")
    if shipY.rect.bottom >= backgroundHeight:
        shipY.setDirection("N")

    print(shipX.dx)

    allSpriteGroup.clear(screen,background)

    allSpriteGroup.draw(screen)

    pygame.display.flip()

Quick rundown, shipX should move when the arrow keys are pressed and shipY moves up and down by itself. Im having an issue where the sprites update only to shipY meaning they will only move up and down. the ShipX sprite will rotate properly and the x and y locations change in the log, but the sprites seem to constantly be attached. I'm stumped and cannot figure out a way to fix this issue. Any help would be great. thank you

Upvotes: 1

Views: 308

Answers (1)

elegent
elegent

Reputation: 4007

To solve the problem change the __init__() method of your Ship sprite class to:

def __init__(self, imgarr, speed, xpos, ypos, direct):
    pygame.sprite.Sprite.__init__(self)
    self.imgarray = imgarr
    self.movepersec = speed
    self.dx = xpos
    self.dy = ypos
    self.direction = direct
    self.image = self.imgarray[self.direction]
    self.rect = self.image.get_rect() #create a *new* rect-object 

The important thing is that every time you create a new instance (i.e. a new sprite) you must also create a new pygem.rect object (see above code).

In your code every Ship object (shipX and shipY) used the same pygem.rect object which was passed to it via the __init__() method (rect argument).
When you called the update() method, one of the two ships changed the rect.centerx and rect.centery attributes of the same rect. That´s the reason why PyGame drew both sprites on the same (rect)-position (allSpriteGroup.draw(screen)).

When you create now a new ship, be aware that the constructor (__init__() method) does not need the rect argument anymore:

shipX = Ship(imgarray, movepersec, 100, 100, "E")

By default shipX appears in the top left corner, because the .get_rect() method returns a pygame.rect which location is set to (0, 0). To set the position of shipX according to the passed xpos and ypos arguments in the constructor, add these two lines after the craetion of the self.rect object:

self.rect.centerx = self.dx
self.rect.centery = self.dy

I hope this helps :)

Upvotes: 1

Related Questions