Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

AttributeError: 'str' object has no attribute 'update'

I am making a sandbox(with sand) and I stumbled on an error in this line:

for grain in sand:
            grain.update()

The sand variable is a dictionary, and I don’t know what went wrong. If you need further clarity, comment.
The full program is:

import pygame
import random

WIDTH, HEIGHT = 640, 360
FPS = 60

WHITE = (255, 255, 255)
SAND = (194, 178, 128)

GRAVITY = 0.5 # increased gravity

def main_program():
    global sand
    pygame.init()

    game_display = pygame.display.set_mode((WIDTH, HEIGHT))
    pygame.display.set_caption("Sandbox")

    is_crashed = False
    clock = pygame.time.Clock()

    font = pygame.font.SysFont("Arial", 32)

    sand_grain = pygame.Surface((4, 4))
    pygame.draw.rect(sand_grain, SAND, (0, 0, 4, 4))

    sand = {}
    sand_id = 0

    while not is_crashed:
        mouse_x, mouse_y = pygame.mouse.get_pos()
        mouse_held = pygame.mouse.get_pressed()[0]

        if mouse_held:
            sand[str(sand_id)] = Grain(mouse_x, mouse_y)
            sand_id += 1
        for grain in sand:
            grain.update()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_crashed = True
            # handle mouse button down event
            if event.type == pygame.MOUSEBUTTONDOWN:
                # get the position and button of the mouse event
                pos = event.pos
                button = event.button
                # get a list of all grains that are under the mouse cursor
                clicked_grains = [g for g in sand.values() if g.rect.collidepoint(pos)]
                # if there are any grains clicked
                if clicked_grains:
                    # get the topmost grain
                    top_grain = clicked_grains[-1]
                    # if the left mouse button is pressed
                    if button == 1:
                        # set the dragged attribute of the grain to True
                        top_grain.dragged = True
            # handle mouse button up event
            if event.type == pygame.MOUSEBUTTONUP:
                # get the position and button of the mouse event
                pos = event.pos
                button = event.button
                # get a list of all grains that are under the mouse cursor
                clicked_grains = [g for g in sand.values() if g.rect.collidepoint(pos)]
                # if there are any grains clicked
                if clicked_grains:
                    # get the topmost grain
                    top_grain = clicked_grains[-1]
                    # if the left mouse button is released
                    if button == 1:
                        # set the dragged attribute of the grain to False
                        top_grain.dragged = False
        game_display.fill(WHITE)

        for grain in sand.values():
            grain.draw(game_display, sand_grain)

        pygame.display.flip()
        clock.tick(FPS)
    pygame.quit()

class Grain:
    def __init__(self, x, y):
        self.x = x
        self.y = y

        self.yv = 0
        self.xv = random.randint(-2, 2) # added horizontal velocity

        self.rect = pygame.Rect(self.x, self.y, 4, 4)
        self.dragged = False # added dragged attribute
    def update(self):
        global sand
        if self.y > HEIGHT - 4: # check for bottom edge collision
            self.y = HEIGHT - 4
            self.yv = 0
        elif self.y < 0: # check for top edge collision
            self.y = 0
            self.yv = 0
        else:
            self.yv += GRAVITY
        if self.x > WIDTH - 4: # check for right edge collision
            self.x = WIDTH - 4
            self.xv = 0
        elif self.x < 0: # check for left edge collision
            self.x = 0
            self.xv = 0
        else:
            self.xv += random.randint(-1, 1) # add some randomness to horizontal movement
        self.x += self.xv
        self.y += self.yv

        self.rect = pygame.Rect(self.x, self.y, 4, 4)

        for other in sand.values(): # check for collisions with other grains
            if other is not self and self.rect.colliderect(other.rect): # use pygame.Rect.colliderect method
                self.yv = 0
                self.xv = 0
                
                if self.y < other.y:
                    self.y = other.y - 4
                elif self.y > other.y:
                    self.y = other.y + 4
                if self.x < other.x:
                    self.x = other.x - 4
                elif self.x > other.x:
                    self.x = other.x + 4
                break
        # check if the grain is being dragged by the mouse
        if self.dragged:
            # get the current mouse position and movement
            mouse_x, mouse_y = pygame.mouse.get_pos()
            mouse_rel_x, mouse_rel_y = pygame.mouse.get_rel()
            # set the position and velocity of the grain to match the mouse
            self.x = mouse_x
            self.y = mouse_y
            self.xv = mouse_rel_x
            self.yv = mouse_rel_y
            # update the rect of the grain
            self.rect = pygame.Rect(self.x, self.y, 4, 4)
    def draw(self, display, grain):
        display.blit(grain, self.rect)

if __name__ == "__main__":
    main_program()

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Try this

for grain in sand.values():
    grain.update()

I think with sand you are accessing the keys and with sand.values you will access the correct instances

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading