title: pygame inaccurate collision detection and movement
body: <p>I have the beginnings of a game developed in pygame with python3, following tutorials on <a href="https://i.stack.imgur.com/6sk8r.png" rel="nofollow noreferrer">www.teachyourselfpython.com</a> There is a main.py, player.py and walls.py (with player and walls class respectively). The player class contains code for collision detection and movement. Unfortunately, the player does avoid the tile, but on collision, moves to a position on the right hand side of the screen, instead of expected movement (just stopping). Is anyone able to help with the logic of this and correcting the erroneous/undesirable movement on collision. Below, are the three files: main.py, player.py and walls.py. 
  <strong>MAIN.PY</strong></p>
  
  <pre><code>#main.py
  import pygame
  import random
  from player import Player
  from collectable import Collectable
  from walls import Wall
  
  pygame.init()
  BLACK=(0,0,0) 
  WHITE=(255,255,255) 
  RED=(255,0,0) 
  GREEN =(0,255,0)
  
  BLUE=(0,0,255) 
  GOLD=(255,215,0)
  WIDTH=500
  HEIGHT=500
  size= (WIDTH,HEIGHT) 
  screen=pygame.display.set_mode(size)
  pygame.display.set_caption("The Life Game")
  
  
  done = False
  clock=pygame.time.Clock()
  wall_list=pygame.sprite.Group()
  all_sprites = pygame.sprite.Group()
  enemy_list  = pygame.sprite.Group() 
  player=Player()
  player.walls=wall_list
  
  all_sprites.add(player)
  
  
  for i in range(random.randrange(100,200)):
          whiteStar = Collectable(WHITE, 3, 3, "White Star", "Rect")
          whiteStar.rect.x = random.randrange(size[0])
          whiteStar.rect.y = random.randrange(size[1])
          all_sprites.add(whiteStar)
  
  for i in range(50):
  
      enemy = Collectable(RED,6, 6,"Enemy","Ellipse")
      enemy.rect.x = random.randrange(300)
      enemy.rect.y = random.randrange(300)
      enemy_list.add(enemy)
      all_sprites.add(enemy)
  
  coin1 = Collectable(GOLD,50,50,"Coin","Ellipse") 
  coin1.rect.x=440
  coin1.rect.y=0
  all_sprites.add(coin1)
  
  coin2 = Collectable(GOLD,50,50,"Coin","Ellipse")
  coin2.rect.x=0
  coin2.rect.y=440
  all_sprites.add(coin2)
  
  enemy = Collectable(RED,100,100,"Enemy","Ellipse")
  enemy.rect.x=70
  enemy.rect.y=230
  all_sprites.add(enemy)
  
  #Make the walls (x_pos,y_pos, width, height,colour)
  
  
  
  wall=Wall(0,0,10,600,GREEN)
  wall_list.add(wall)
  all_sprites.add(wall_list)
  
  wall = Wall(50, 300, 400, 10,RED)
  wall_list.add(wall)
  all_sprites.add(wall_list)
  
  wall = Wall(10, 200, 100, 10,BLUE)
  wall_list.add(wall)
  all_sprites.add(wall_list)
  
  
  score=0
  health=100
  
  #- - - - - - - - - - - - - -Main Program Loop - - - - - - - - - - - - - - - -
  def main():
          done=False
          score=0
          health=100
          while not done:
  
  
                    #- - - - - - Main event loop (this is where code for handling keyboard and mouse clicks will go)
          #Loop until the user clicks the 'x' button (to close program)
                    for event in pygame.event.get(): #User does something
                              if event.type == pygame.QUIT: #If the user clicked close
                                        done = True  #set the done flag to 'true' to exit the loop
  
                    keys = pygame.key.get_pressed() #checking pressed keys
                    if keys[pygame.K_LEFT]:
                       player.moveLeft(5)
                    if keys[pygame.K_RIGHT]:
                       player.moveRight(5)
                    if keys[pygame.K_UP]:
                       player.moveUp(5)
                    if keys[pygame.K_DOWN]:
                       player.moveDown(5)                
  
  
                   #&gt;&gt;----------DRAW SECTION -----------------------------------
                    #Clear the screen to BLACK. Any drawing commands should be put BELOW this or they will be reased with this command
                    screen.fill(BLACK)
  
  
  
                    #Select the font to be used (size, bold, italics, etc)
                    font_score = pygame.font.SysFont('Calibri',20,True,False)
                    font_health = pygame.font.SysFont('Calibri',20,True,False)
                  #Printing a variable (score or health) to the screen involves converting the score (if integer) to a string first.score_label = font_score.render("Score: " + str(score),True,BLACK)
                    health_label = font_health.render("Health: "+str(health),True,WHITE)
                    score_label = font_score.render("Score: " + str(score),True, WHITE)
                  #Now we can use this line of code to put the image of the text on the screen at a given position
                    screen.blit(score_label,[100,480])
                    screen.blit(health_label,[190,480])
  
  
                     #&gt;&gt;---------UPDATE SECTION / Put the logic of your game here (i.e. how objects move, when to fire them, etc)
  
  
                    all_sprites.update()
  
                    if coin1.collision_with(player):
                           score=score+1
                           coin1.kill()
                           coin1.rect.x=-20
                           coin1.rect.y=-330
  
                    if coin2.collision_with(player):
                           score=score+1
                           coin2.kill()
                           coin2.rect.x=-20
                           coin2.rect.y=-330
  
                    if enemy.collision_with(player):
                          health=health-25
                          enemy.kill()
                          enemy.rect.x=-20
                          enemy.rect.y=-330
  
                    enemy.update()
  
  
  
  
  
           #-------------PRINTING VARIABLES LIKE SCORE TO SCREEN
                    #Any drawing/graphics code should go here
                    all_sprites.draw(screen)
  
                    #Update the screen to show whatever you have drawn
                    pygame.display.flip()
  
                    #Set the frames per second (e.g. 30, 60 etc)
                    clock.tick(120)
  
  main()
  </code></pre>
  
  <p><strong>PLAYER.PY</strong></p>
  
  <pre><code>import pygame
  import random
  from walls import Wall
  
  class Player(pygame.sprite.Sprite): 
      #-------------------Define Variables here
      speed=0
      #------------------Initialise Constructor
      def __init__(self): 
          pygame.sprite.Sprite.__init__(self)
          self.image=pygame.image.load("player.png") 
          self.rect = self.image.get_rect()
  
          #SET THE INITIAL SPEED TO ZERO
          self.change_x = 0
          self.change_y = 0
  
          #--------------Fetch the rectangle object that has the dimensions of the image
          self.rect =self.image.get_rect()
          #---------------Define movement
      def moveRight(self,pixels):
          self.rect.x+=pixels
      def moveLeft(self,pixels):
          self.rect.x-=pixels
      def moveUp(self,pixels):
          self.rect.y-=pixels
      def moveDown(self,pixels):
          self.rect.y+=pixels
  
      # Make our top-left corner the passed-in location.
      def settopleft():
          self.rect = self.image.get_rect()
          self.rect.y = y
          self.rect.x = x
  
          # Set speed vector
          self.change_x = 0
          self.change_y = 0
          self.walls = None
  
      def changespeed(self, x, y):
          """ Change the speed of the player. """
          self.change_x += x
          self.change_y += y
  
  
      def update(self):
          # Did this update cause us to hit a wall?
          block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
          for block in block_hit_list:
              # If we are moving right, set our right side to the left side of
              # the item we hit
              if self.change_x &gt; 0:
                  self.rect.right = block.rect.left
              else:
                  # Otherwise if we are moving left, do the opposite.
                  self.rect.left = block.rect.right
  
          # Move up/down
                  self.rect.y += self.change_y
  
          # Check and see if we hit anything
          block_hit_list = pygame.sprite.spritecollide(self, self.walls, False)
          for block in block_hit_list:
  
              # Reset our position based on the top/bottom of the object.
              if self.change_y &gt; 0:
                  self.rect.top = block.rect.top
              else:
                  self.rect.top = block.rect.bottom
  </code></pre>
  
  <p><strong>WALLS.PY</strong></p>
  
  <pre><code>import pygame
  
  class Wall(pygame.sprite.Sprite):
      #Wall a player can run into
      def __init__(self, x, y, width, height,colour):
          #Constructor fo rthe wall that the player can run into
          #call the parent's constructor
          super().__init__()
  
          #Make a green wall, of the size specified in paramenters
          self.image=pygame.Surface([width,height])
          self.image.fill(colour)
  
          #Make the "passed-in" location ,the top left corner
          self.rect=self.image.get_rect()
          self.rect.y=y
          self.rect.x=x
  </code></pre>
  
  <p>Attached, area also images for player and bg: <a href="https://i.stack.imgur.com/6sk8r.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/6sk8r.png" alt="player"></a><a href="https://i.stack.imgur.com/m6Efu.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/m6Efu.jpg" alt="background image"></a></p>