title: Friction and gravity in pygame
body: <p>I want player1 to have a constant downward acceleration acting on him. I tried to do it a couple ways, but it didn't really work how I wanted it to. When I give player1 velocity in the up direction, he keeps going higher and higher. I tried changing the velocity and gravity values and it looks a little better, but I'm not sure if it's right. I also want there to be a friction force acting on player1 when he's on the bottom of the screen, but because friction depends on normal force, which depends on gravity (Correct me if I'm wrong), I can't really do that yet, so I just have a constant friction acting on player1, but that acts kind of "weird" too. I want it to stop player1 when the velocity reaches 0, not reverse the acceleration.</p>
  
  <pre><code>import sys
  import pygame
  
  pygame.init()
  
  screen_width = 640
  screen_height = 480
  screen = pygame.display.set_mode((screen_width, screen_height))
  screen_rect = screen.get_rect()
  
  clock = pygame.time.Clock()
  
  fps = 30
  
  
  class Character(object):
      def __init__(self, surface, velo, accel, gravity, friction):
          self.surface = surface
          self.velo = velo
          self.accel = accel
          self.gravity = gravity
          self.friction = friction
          self.timestep = 1/fps
          self.vel = (0, 0)
          self.pos = ((screen_width / 2), (screen_height / 2))
          self.size = (10, 10)
  
      def velocity_right(self):
          self.pos = (self.pos[0] + self.velo, self.pos[1])
  
      def velocity_left(self):
          self.pos = (self.pos[0] - self.velo, self.pos[1])
  
      def velocity_up(self):
          self.pos = (self.pos[0], self.pos[1] - self.velo)
  
      def velocity_down(self):
          self.pos = (self.pos[0], self.pos[1] + self.velo)
  
      def velocity(self):
          keys = pygame.key.get_pressed()
          if keys[pygame.K_i]:
              self.velocity_up()
          if keys[pygame.K_j]:
              self.velocity_left()
          if keys[pygame.K_k]:
              self.velocity_down()
          if keys[pygame.K_l]:
              self.velocity_right()
  
      def accelerate_right(self):
          self.vel = (self.vel[0] + self.accel, self.vel[1])
          self.pos = (self.pos[0] + self.vel[0], self.pos[1])
  
      def accelerate_left(self):
          self.vel = (self.vel[0] - self.accel, self.vel[1])
          self.pos = (self.pos[0] + self.vel[0], self.pos[1])
  
      def accelerate_up(self):
          self.vel = (self.vel[0], self.vel[1] - self.accel)
          self.pos = (self.pos[0], self.pos[1] + self.vel[1])
  
      def accelerate_down(self):
          self.vel = (self.vel[0], self.vel[1] + self.accel)
          self.pos = (self.pos[0], self.pos[1] + self.vel[1])
  
      def accelerate(self):
          keys = pygame.key.get_pressed()
          if keys[pygame.K_w]:
              self.accelerate_up()
          if keys[pygame.K_a]:
              self.accelerate_left()
          if keys[pygame.K_s]:
              self.accelerate_down()
          if keys[pygame.K_d]:
              self.accelerate_right()
  
          if self.pos[0] &lt;= 0 or self.pos[0] &gt;= screen_width:
              self.vel = (self.vel[0] * -1, self.vel[1])
  
          if self.pos[1] &lt;= 0 or self.pos[1] &gt;= screen_height:
              self.vel = (self.vel[0], self.vel[1] * -1)
  
          self.character = pygame.Rect((self.pos[0], self.pos[1]), self.size)
          self.character.clamp_ip(screen_rect)
  
      def display(self):
          pygame.draw.rect(self.surface, (255, 255, 255), self.character)
  
      def reset(self):
          (x_pos, y_pos) = pygame.mouse.get_pos()
          self.pos = (x_pos, self.pos[1])
          self.pos = (self.pos[0], y_pos)
          self.vel = (0, 0)
  
      def apply_gravity(self):
          self.vel = (self.vel[0], self.vel[1] + self.accel)
          self.pos = (self.pos[0], self.pos[1] + self.vel[1])
          # self.vel = (self.vel[0], self.vel[1] + self.gravity * self.timestep)
          # self.pos = (self.pos[0], self.pos[1] + self.vel[1] * self.timestep + 0.5 * self.gravity * self.timestep**2)
  
      def apply_friction(self):
          keys = pygame.key.get_pressed()
          if keys[pygame.K_w] or keys[pygame.K_i]:
              self.vel = (self.vel[0], self.vel[1] + self.friction)
              self.pos = (self.pos[0], self.pos[1] + self.vel[1])
          if keys[pygame.K_a] or keys[pygame.K_j]:
              self.vel = (self.vel[0] + self.friction, self.vel[1])
              self.pos = (self.pos[0] + self.vel[0], self.pos[1])
          if keys[pygame.K_s] or keys[pygame.K_k]:
              self.vel = (self.vel[0], self.vel[1] - self.friction)
              self.pos = (self.pos[0], self.pos[1] + self.vel[1])
          if keys[pygame.K_d] or keys[pygame.K_l]:
              self.vel = (self.vel[0] - self.friction, self.vel[1])
              self.pos = (self.pos[0] + self.vel[0], self.pos[1])
  
  
  def main():
      player1 = Character(screen, 10, 1, .5, .4)
      while True:
          for event in pygame.event.get():
                  if event.type == pygame.QUIT:
                      pygame.quit()
                      sys.exit()
                  elif event.type == pygame.MOUSEBUTTONDOWN:
                      player1.reset()
  
          player1.apply_gravity()
          player1.apply_friction()
  
          player1.velocity()
          player1.accelerate()
  
          screen.fill((0, 0, 0))
  
          player1.display()
  
          pygame.display.update(screen_rect)
          clock.tick(fps)
  
  if __name__ == "__main__":
      main()
  </code></pre>