Cannon Sprites Lag Game Instead Of Rotating Towards Player

Viewed 73

in my main loop, this is what I did V I told all my enemies to rotate towards the player but it's lagging the game and the cannons aren't rotating to the player Lags Game + Sprites Not Rotating -- as you can see they aren't rotating and for some reason, it's making my game lag to

# this goes inside the main loop and looks for
      
            for enemyshoot in enemyshooting:
                enemyshoot.lookAt((playerman.x, playerman.y)) 

                 # even if I do lookAt((playerman.x,playerman.y)) instead of putt enemyshoot.lookAt they still don't rotate and my game still lags

my enemyshoot class


    #-------------------------------- enemy shoots left and right

    shotsright = pygame.image.load("canss.png")
    class enemyshoot:
        def __init__(self,x,y,height,width,color):
            self.x = x
            self.y =y
            self.height = height
            self.width = width
            self.color = color
            self.rect = pygame.Rect(x,y,height,width)
            self.health = 10
            self.hitbox = (self.x + -20, self.y + 30, 31, 57)
           #-------------------------------------------------------
            # Make a Reference Copy of the bitmap for later rotation
            self.shootsright = pygame.image.load("canss.png")
            self.shootsright = pygame.transform.scale(self.shootsright,(self.shootsright.get_width()-150,self.shootsright.get_height()-150))            
            self.image    = self.shootsright
            self.rect     = self.image.get_rect()
            self.position = pygame.math.Vector2( ( x, y ) )
        def draw(self):
            self.rect.topleft = (self.x,self.y)
            window.blit(self.shootsright,self.rect)
            self.hits = (self.x + 20, self.y, 28,60)
            pygame.draw.rect(window, (255,0,0), (self.hitbox[0], self.hitbox[1] - 60, 100, 10)) # NEW
            pygame.draw.rect(window, (0,255,0), (self.hitbox[0], self.hitbox[1] - 60, 100 - (5 * (10 - self.health)), 10))
            self.hitbox = (self.x + 100, self.y + 160, 51, 65)
        def lookAt( self, coordinate ):
            # Rotate image to point in the new direction
            delta_vector  = coordinate - self.position
            radius, angle = delta_vector.as_polar()
            self.image    = pygame.transform.rotozoom( self.shootsright, -angle, 1 )
            # Re-set the bounding rectangle and position since 
            # the dimensions and centroid will have (probably) changed.
            current_pos      = self.rect.center
            self.rect        = self.image.get_rect()
            self.rect.center = current_pos
            


            
    black = (0,0,0)
    enemyshooting = []
    platformGroup = pygame.sprite.Group
    platformList = []
    level = ["                                                                                                                        p               p         p                         p                        p        ",
             "                                       ",
             "                             ",
             "                                      ",
             "                                  ",
             "                           ",
             "                                      ",
             "                                      ",
             "                                    ",
             "                                   ",
             "                    ",]
    for iy, row in enumerate(level):
        for ix, col in enumerate(row):
            if col == "p":
                new_platforms = enemyshoot(ix*10, iy*50, 10,10,(255,255,255))
                enemyshooting.append(new_platforms)
                

2 Answers

You are saving the result of pygame.transform.rotozoom( self.shootsright, -angle, 1 ) to self.image, while in the draw function you are displaying self.shootsright. You have to blit self.image instead. Also, if you are iterating through each enemy, and making them rotate every time the for loop targets them, instead of rotating them just once, the sprite will rotate infinitely at the max speed your CPU allows the script, and that is why it is lagging. You have to target only the enemies that are not looking at the player.

This is how I would do it:

enemyshoot class:

  #-------------------------------- enemy shoots left and right

    shotsright = pygame.image.load("canss.png")
    class enemyshoot:
        def __init__(self,x,y,height,width,color):
            self.x = x
            self.y =y
            self.height = height
            self.width = width
            self.color = color
            self.rect = pygame.Rect(x,y,height,width)
            self.health = 10
            self.hitbox = (self.x + -20, self.y + 30, 31, 57)
           #-------------------------------------------------------
            # Make a Reference Copy of the bitmap for later rotation
            self.shootsright = pygame.image.load("canss.png")
            self.shootsright = pygame.transform.scale(self.shootsright,(self.shootsright.get_width()-150,self.shootsright.get_height()-150))            
            self.image    = self.shootsright
            self.rect     = self.image.get_rect()
            self.position = pygame.math.Vector2( ( x, y ) )
            self.isLookingAtPlayer = False
        def draw(self):
            self.rect.topleft = (self.x,self.y)
            window.blit(self.image, self.rect)
            self.hits = (self.x + 20, self.y, 28,60)
            pygame.draw.rect(window, (255,0,0), (self.hitbox[0], self.hitbox[1] - 60, 100, 10)) # NEW
            pygame.draw.rect(window, (0,255,0), (self.hitbox[0], self.hitbox[1] - 60, 100 - (5 * (10 - self.health)), 10))
            self.hitbox = (self.x + 100, self.y + 160, 51, 65)
        def lookAt( self, coordinate ):
            # Rotate image to point in the new direction
            delta_vector  = coordinate - self.position
            radius, angle = delta_vector.as_polar()
            self.image    = pygame.transform.rotate(self.shootsright, -angle)
            # Re-set the bounding rectangle and position since 
            # the dimensions and centroid will have (probably) changed.
            current_pos      = self.rect.center
            self.rect        = self.image.get_rect()
            self.rect.center = current_pos
            


            
    black = (0,0,0)
    enemyshooting = []
    platformGroup = pygame.sprite.Group
    platformList = []
    level = ["                                                                                                                        p               p         p                         p                        p        ",
             "                                       ",
             "                             ",
             "                                      ",
             "                                  ",
             "                           ",
             "                                      ",
             "                                      ",
             "                                    ",
             "                                   ",
             "                    ",]
    for iy, row in enumerate(level):
        for ix, col in enumerate(row):
            if col == "p":
                new_platforms = enemyshoot(ix*10, iy*50, 10,10,(255,255,255))
                enemyshooting.append(new_platforms)

for loop:

# this goes inside the main loop and looks for
      
            for enemyshoot in enemyshooting:
                if not enemyshoot.isLookingAtPlayer:
                    enemyshoot.lookAt((playerman.x, playerman.y)) 

I am not sure how would you detect if the sprite is looking at the player, but I guess it's just comparing the rotation vector of the enemy to the vector between the player and the enemy, and if they are not the same then call lookAt().

@CiroGarcĂ­a has provided assitance already. I am just going to add a suggestion. It seems like you are not scaling the canon images, just rotating them. If that is the case you can likely significantly improve your performance by prerotating the images that you are likely to need and then just selecting from those when you need to draw the canon.

From the video it looks like you do not need the full 360 degrees since the player is always below them, it would be at most 180 and looks like it would be only about a 120 degree or so range (from the angle of rotation required for the cannon on the far right to point to the player when on the far left side, to the angle of rotation require for the canon on the far left side to point to the player when on the far right). Also the number of images within that range can be reduced as well. You probably could not tell the difference if you only had an image for every 5 degrees and then selected the image rotated closest to the angle needed. A 120 degree range with one image every 5 degrees is 120/5, with 1 extra for the other end of the range. That is only 25 (= 120/5 + 1) images to keep around for fast display.

You figure out a which angles you need and pre-rotate those images and save them for later use.

Edit:

I also just noticed from your video that the canon images are not vertically aligned. They look like they are rotated slightly counterclockwise from the vertical (as a guess about 10-15 degrees or so). You would have to take that rotation into account and add or subtract it from the rotation amount when you are deciding how much to rotate them to make them point at the player.

Related