Search code examples
pythonpygame

How Do I Fix This Movement Pygame


I'm working with movements and I have made the red block follow the white block which is the player when ever the white block changes directions I have the red block also change directions is there a way I could make it smoothier other then it teleporting the tail to the direction of the player? Video Link

here is how the red tail moves based on the white block if the player is moving down the x and y of the tail changes and same for the up ,left,right I want a better way to do this without it instantly teleporting to those position like smoothly move there

    if down:
       #-- the tail red change directions
        tail.y = player1.y - 80
        tail.x = player1.x

    if up:
       #-- the tail red change directions
        tail.y = player1.y + 80
        tail.x = player1.x
        
    if left:
       #-- the tail red change directions
        tail.y = player1.y 
        tail.x = player1.x + 80

    if right:
       #-- the tail red change directions
        tail.y = player1.y 
        tail.x = player1.x - 80

my full code


import pygame
pygame.init()


# draw the iwndow
width = 500
height = 750

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


# the player class
class player:
    def __init__(self,x,y,height,width,color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.rect = pygame.Rect(x,y,height,width)
        self.speed = 5
    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.rect)

# display the player
color = (255,255,255)
player1 = player(180,190,40,40,color)


# bg

bg = pygame.image.load('2.png')

# the colision to determine the direction the player should move
class player:
    def __init__(self,x,y,height,width,color):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.rect = pygame.Rect(x,y,height,width)
        self.speed = .9
    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.rect)

# display the player
color = (255,255,255)
tailcolor = (176, 58, 46)
player1 = player(180,170,50,50,color)

tail = player(100,170,50,50,tailcolor)

def draw():
    window.fill((0,0,0))
    window.blit(bg,(0,0))
    player1.draw()

    
    tail.draw()
    

# make movements True
right = False
left = False
up = False
down = False
only_up = False
only_left = False

# get position
pos = True
pos2 = 0
# the main loop
run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False




    # check for key press
    keys = pygame.key.get_pressed()


    if down:
       #-- the tail red change directions
        tail.y = player1.y - 80
        tail.x = player1.x

    if up:
       #-- the tail red change directions
        tail.y = player1.y + 80
        tail.x = player1.x
        
    if left:
       #-- the tail red change directions
        tail.y = player1.y 
        tail.x = player1.x + 80

    if right:
       #-- the tail red change directions
        tail.y = player1.y 
        tail.x = player1.x - 80
        
    #--------------------------------------------------- player movement
    if left == False:
        if keys[pygame.K_RIGHT]:
            if  not keys[pygame.K_UP]:
                if not keys[pygame.K_DOWN]:
                    right = True


    if right:
        left = False
        down = False
        up = False
        player1.x += player1.speed



        
    if right == False:
        if keys[pygame.K_LEFT]:
            if not keys[pygame.K_UP]:
                if not keys[pygame.K_DOWN]:
                    left = True

    if left:
        right = False
        down = False
        up = False
        player1.x -= player1.speed
        


    if down == False:
        if keys[pygame.K_UP]:
            up = True       
    if up:
        down = False
        left = False
        right = False
        
        player1.y -= player1.speed


        
    if up == False:
        if keys[pygame.K_DOWN]:
            down = True

    if down:
        up = False
        left = False
        right = False
        player1.y += player1.speed


    

        
    #--------------------------------------------------- player movement



            
    # show everything drawn
    draw()

    pygame.display.update()

pygame.quit()



Solution

  • I think you can achieve that by using some sort of delay. Instead of getting the position of the tail based on the current position of the player, you want to get the position of the tail based on an "old position of the player".

    Also, the delay should be a variable that you can change at will later, in case you want to adjust how close the tail follows the player.

    Here is what I would try:

    • Outside the infinite loop, define a variable called tail_delay, and assign it a specific amount of time.
    • You can have an object to record the "current position" of player1 with timestamps (it will be a collection of positions in the end). That object, let's call it player1_positions_record, will be updated constantly in the infinite loop (this can be a waste of memory - don't save all positions, you only need a few seconds, and older than that you discard).
    • In the infinite loop, assign the position of the tail based on the tail_delay and the player1_positions_record. That way you'll use a past position of player1.

    As mentioned in the comments, this is not a perfect solution but it works:

    import pygame
    from datetime import datetime, timedelta
    pygame.init()
    
    # tail delay in seconds
    tail_delay=timedelta(seconds=0.3)
    
    # draw the iwndow
    width = 900
    height = 1200
    
    window = pygame.display.set_mode((height,width))
    
    
    # the player class
    class player:
        def __init__(self,x,y,height,width,color):
            self.x = x
            self.y = y
            self.width = width
            self.height = height
            self.color = color
            self.rect = pygame.Rect(x,y,height,width)
            self.speed = 5
        def draw(self):
            self.rect.topleft = (self.x,self.y)
            pygame.draw.rect(window,self.color,self.rect)
    
    # display the player
    color = (255,255,255)
    player1 = player(180,190,40,40,color)
    
    
    # bg
    
    bg = pygame.image.load('2.png')
    
    # the colision to determine the direction the player should move
    class player:
        def __init__(self,x,y,height,width,color):
            self.x = x
            self.y = y
            self.width = width
            self.height = height
            self.color = color
            self.rect = pygame.Rect(x,y,height,width)
            self.speed = .9
        def draw(self):
            self.rect.topleft = (self.x,self.y)
            pygame.draw.rect(window,self.color,self.rect)
    
    # display the player
    color = (255,255,255)
    tailcolor = (176, 58, 46)
    player1 = player(180,170,50,50,color)
    
    tail = player(100,170,50,50,tailcolor)
    
    def draw():
        window.fill((0,0,0))
        window.blit(bg,(0,0))
        player1.draw()
    
        
        tail.draw()
        
    
    # make movements True
    right = False
    left = False
    up = False
    down = False
    only_up = False
    only_left = False
    
    # get position
    pos = True
    pos2 = 0
    # the main loop
    run = True
    
    player1_positions_record=[]
    test_time=datetime.now()
    
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
        
        # add current position, and delete the positions that are old
        # in 1 second, I counted 270 timestamps approx, so I will cut the timestamps in 500 (don't think we need more than that)
        player1_positions_record.append((datetime.now(), (player1.x, player1.y)))
        if len(player1_positions_record) > 500:
            player1_positions_record = player1_positions_record[-500:]
        # now it's time to find the position of the tail. It will be an old position of the player
        right_now=datetime.now()
        for position in player1_positions_record:
            position_timestamp=position[0]
            print(type(position_timestamp))
            if position[0]>right_now-tail_delay:
                tail.y = position[1][1] # second element of the tuple containing the old position 
                tail.x = position[1][0] # first element
                break
    
        # check for key press
        keys = pygame.key.get_pressed()
    
    
        # if down:
        #    #-- the tail red change directions
        #     tail.y = player1.y - 80
        #     # tail.x = player1.x
    
        # if up:
        #    #-- the tail red change directions
        #     tail.y = player1.y + 80
        #     # tail.x = player1.x
            
        # if left:
        #    #-- the tail red change directions
        #     tail.y = player1.y 
        #     tail.x = player1.x + 80
    
        # if right:
        #    #-- the tail red change directions
        #     tail.y = player1.y 
        #     tail.x = player1.x - 80
            
        #--------------------------------------------------- player movement
        if left == False:
            if keys[pygame.K_RIGHT]:
                if  not keys[pygame.K_UP]:
                    if not keys[pygame.K_DOWN]:
                        right = True
    
    
        if right:
            left = False
            down = False
            up = False
            player1.x += player1.speed
    
    
    
            
        if right == False:
            if keys[pygame.K_LEFT]:
                if not keys[pygame.K_UP]:
                    if not keys[pygame.K_DOWN]:
                        left = True
    
        if left:
            right = False
            down = False
            up = False
            player1.x -= player1.speed
            
    
    
        if down == False:
            if keys[pygame.K_UP]:
                up = True       
        if up:
            down = False
            left = False
            right = False
            
            player1.y -= player1.speed
    
    
            
        if up == False:
            if keys[pygame.K_DOWN]:
                down = True
    
        if down:
            up = False
            left = False
            right = False
            player1.y += player1.speed
    
    
        
    
            
        #--------------------------------------------------- player movement
    
    
    
                
        # show everything drawn
        draw()
    
        pygame.display.update()
    
    pygame.quit()