Home > Software design >  Pygame images glitching appearing in corner. May be RECT issue?
Pygame images glitching appearing in corner. May be RECT issue?

Time:08-10

Making a simple game that runs itself with ducks eating bread. It works fine but the images "glitch" or blit all over the screen, i have narrowed it down to: whenever a bread is "eaten" a new bread appears and blits all over the screen before settling down

Code in question:

            for BreadPos in breadxy:
                if (((Ducky.xpos - BreadPos[0])   (Ducky.ypos - BreadPos[1]))) > -5:
                
                    del FoodList[breadxy.index(BreadPos)]

                    Ducky.hunger  = 60
                    
                    FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
                    #this line here is supposed to be indented properly but i am seemingly bad at this stack overflow thing. 



Here is my code in its entirety:

import pygame
import pygame, sys
from pygame.locals import *
import random

def main():
    pygame.init()

    (width,height) = (640,640)

    clock = pygame.time.Clock()

    DISPLAY = pygame.display.set_mode((width,height))

    blue= (0,60,200)

    DISPLAY.fill(blue)

    #pictures and spirtes

    DuckPic = pygame.image.load("Duck Sprite.jpg")
    DuckPic = pygame.transform.scale(DuckPic, (128, 72))

    BreadPic = pygame.image.load("breadpic.jpg")
    BreadPic = pygame.transform.scale(BreadPic, (128, 72))

    class Food(pygame.sprite.Sprite):
        def __init__(self, xpos,ypos):
            super().__init__()
            self.xpos = xpos
            self.ypos = ypos
            self.image = BreadPic
            self.rect = self.image.get_rect()

    FoodList = []

    for i in range (10):
        FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
    
    class Duck(pygame.sprite.Sprite):
        def __init__(self,xpos,ypos,speed,hunger,movement):
            super().__init__()
            self.xpos = xpos
            self.ypos = ypos
            self.image = DuckPic
            self.rect = self.image.get_rect()
            self.speed = speed
            self.hunger = hunger
            self.movement = movement

    Ducks = []

    for i in range(1):
        Ducks.append(Duck(xpos = random.randint(0, 320), ypos = random.randint(0, 320), speed =(random.randint(1,3)), hunger = 1000, movement = random.randint(1,100)))


    ###------------ GAME STUFF INSTANCES HAPPENING

    while True:
        clock.tick(60)

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

        if FoodList == []:
            print("ducks ate all the bread")
            pygame.quit()
            sys.exit()

        if Ducks == []:
            print("all ducks died")
            pygame.quit()
            sys.exit()
        

        #display screen then food then ducks
        DISPLAY.fill(blue)

        breadxy = []

        #gets xy pos of all food items 
        for i,FoodItem, in enumerate(FoodList):
            xyList = [FoodItem.xpos , FoodItem.ypos]
            breadxy.append(xyList)
        
        for i,Ducky in enumerate(Ducks):

            closestlist = [] #reset list of closest breads for all ducks

            for count,j in enumerate(breadxy):

                
               
                closestlist.append(((Ducky.xpos - j[0])   (Ducky.ypos - j[1])))
                #closest list shows a value of how close a duck is to the bread 
                #where 0 or -1 = best score 

            indexofBread = closestlist.index(max(closestlist))
            
            print(f"I'm moving to bread {indexofBread} with value of {max(closestlist)} which is at {FoodList[indexofBread].xpos,FoodList[indexofBread].ypos}, my postion is {Ducky.xpos, Ducky.ypos} other values include = {closestlist}")

            if True:
            #move duck to closest bread
                if Ducky.xpos < FoodList[indexofBread].xpos:
                    Ducky.xpos  = 1 * Ducky.speed
                    
                if Ducky.xpos > FoodList[indexofBread].xpos:
                    Ducky.xpos -= 1 * Ducky.speed

                if Ducky.ypos > FoodList[indexofBread].ypos:
                    Ducky.ypos -= 1 * Ducky.speed   

                if Ducky.ypos< FoodList[indexofBread].ypos:
                    Ducky.ypos  = 1 * Ducky.speed            

            Ducky.hunger = Ducky.hunger - 1*Ducky.speed
            #duck hunger goes down, faster duck looses more hunger

            if Ducky.hunger < 0: #if duck at 0 hunger he dies :(
                del Ducks[i]


            #display the bread

            #check for collision thorugh seeing if score is good
            for BreadPos in breadxy:
                if (((Ducky.xpos - BreadPos[0])   (Ducky.ypos - BreadPos[1]))) > -5:
                
                    del FoodList[breadxy.index(BreadPos)]

                    Ducky.hunger  = 60
                    
                    FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
                    #print(len(FoodList))
                        
            #print(Ducky.hunger)

            for FoodItem in (FoodList):
            
                DISPLAY.blit(FoodItem.image, (FoodItem.xpos, FoodItem.ypos))

            #DISPLAY DUCK

            DISPLAY.blit(Ducky.image, (Ducky.xpos, Ducky.ypos))
        
        pygame.display.update()
            
        #make the screen
        
    
    
main()

CodePudding user response:

So it looks like the issue is the tracking of the FoodList index via the breadxy list.

The breadxy tracking is an index into FoodList, so the bread that was eaten can be removed from the list. But as soon as the breads are removed, the indexes into the list are no longer correct. The "eating" loop doesn't stop checking after an item is consumed, so theoretically this loop can be repeated multiple times. After the first del(), no index is valid. Sometimes it will crash because the index could be more than the new (shorted) length of the list.

I couldn't work out the distance algorithm!? So I substituted it with a member function on Duck that calculates the ducks

CodePudding user response:

The issue is with how you defined the collision distance. From your formula (Ducky.xpos - BreadPos[0]) (Ducky.ypos - BreadPos[1]) > -5, it basically means you want the bread on the upper and left portion of your duck deleted, and consequently all the bread gets crowded at the lower-right portion of the screen.

Because of that issue, a food is randomly generated and blit to screen in 1 frame, but then on the next frame that food is deleted because of your distance formula condition and then another food is randomly generated and blit to screen.

Below is a sample manhattan distance formula. You may also apply pythagorean/euclidian distance formula. Also, if you want to go deeper with pygame, there are built-in collision functions such as colliderect, collidepoint, etc.

for BreadPos in breadxy:
    distance = abs(Ducky.xpos - BreadPos[0])   abs(Ducky.ypos - BreadPos[1])
    if distance < 5:
        del FoodList[breadxy.index(BreadPos)]
        Ducky.hunger  = 60
        FoodList.append(Food(random.randint(30, 600), random.randint(30, 600)))
  • Related