{"id":"animation-moving","slug":"moving","title":"Moving pictures","text":"An **animation** is a series of pictures shown quickly one after another, each a little different from the one before, and the eye sees movement. A pygame program already has the series of pictures: the frames of its main loop. To animate something, keep its position in variables and change them a little on every round of the loop.\n\n```asset robot.png\n40x40\n```\n\n```python\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 0\ny = 100\nclock = pygame.time.Clock()\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (x, y))\n    pygame.display.flip()\n\n    x += 2\n    clock.tick(60)\n```\n\n```window-shot\n{\"image\":\"lessons/windows/ccd00e1e898b9a5b.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":60,\"log\":\"fill (0, 0, 0)\\nblit robot.png at (118, 100)\",\"ended\":\"closed\",\"code\":\"import pygame\\n\\npygame.init()\\nwindow = pygame.display.set_mode((320, 240))\\nrobot = pygame.image.load(\\\"robot.png\\\")\\n\\nx = 0\\ny = 100\\nclock = pygame.time.Clock()\\n\\nwhile True:\\n    for event in pygame.event.get():\\n        if event.type == pygame.QUIT:\\n            exit()\\n\\n    window.fill((0, 0, 0))\\n    window.blit(robot, (x, y))\\n    pygame.display.flip()\\n\\n    x += 2\\n    clock.tick(60)\\n\",\"window\":{\"frames\":60,\"events\":[]},\"assets\":[\"robot.png\"]}\n```\n\nThe variables `x` and `y` hold the robot's position. They get their first values once, before the main loop. Every round draws the robot where it is, shows the frame, and then moves it: `x += 2`. So the first frame shows the robot at x = 0, the second at 2 and the third at 4: frame number n shows it at 2 × (n - 1). The window above showed 60 frames, so its last frame has the robot at x = 118:\n\n```text\nfill (0, 0, 0)\nblit robot.png at (118, 100)\n```\n\n### Fill every frame\n\nThe `fill` at the start of each frame paints over the frame before. Without it, the old pictures stay in the window and the robot smears a trail behind it. Here the window is filled only once, before the main loop:\n\n```python\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 0\nclock = pygame.time.Clock()\nwindow.fill((0, 0, 0))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.blit(robot, (x, 100))\n    pygame.display.flip()\n\n    x += 2\n    clock.tick(60)\n```\n\n```window-shot\n{\"image\":\"lessons/windows/c871a97ecff9e128.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":20,\"log\":\"fill (0, 0, 0)\\nblit robot.png at (0, 100)\\nblit robot.png at (2, 100)\\nblit robot.png at (4, 100)\\nblit robot.png at (6, 100)\\nblit robot.png at (8, 100)\\nblit robot.png at (10, 100)\\nblit robot.png at (12, 100)\\nblit robot.png at (14, 100)\\nblit robot.png at (16, 100)\\nblit robot.png at (18, 100)\\nblit robot.png at (20, 100)\\nblit robot.png at (22, 100)\\nblit robot.png at (24, 100)\\nblit robot.png at (26, 100)\\nblit robot.png at (28, 100)\\nblit robot.png at (30, 100)\\nblit robot.png at (32, 100)\\nblit robot.png at (34, 100)\\nblit robot.png at (36, 100)\\nblit robot.png at (38, 100)\",\"ended\":\"closed\",\"code\":\"import pygame\\n\\npygame.init()\\nwindow = pygame.display.set_mode((320, 240))\\nrobot = pygame.image.load(\\\"robot.png\\\")\\n\\nx = 0\\nclock = pygame.time.Clock()\\nwindow.fill((0, 0, 0))\\n\\nwhile True:\\n    for event in pygame.event.get():\\n        if event.type == pygame.QUIT:\\n            exit()\\n\\n    window.blit(robot, (x, 100))\\n    pygame.display.flip()\\n\\n    x += 2\\n    clock.tick(60)\\n\",\"window\":{\"frames\":20,\"events\":[]},\"assets\":[\"robot.png\"]}\n```\n\nIts window as text has a `blit` line for every frame, since nothing has painted over them.\n\n### The clock\n\n`clock = pygame.time.Clock()` makes a **clock**, and `clock.tick(60)` at the end of each round keeps the loop from going round more than 60 times a second: when a round took less than a 60th of a second, `tick` waits for the rest of it. That's 60 **frames per second** (FPS), a common speed for games. Without the clock, the loop would run as fast as the computer can go. The robot would cross the window in a blink, and at a different speed on every computer. With the clock, the speed is easy to work out: 2 pixels per frame at 60 frames per second is 120 pixels per second.\n\nMake the clock once, before the main loop, and call `tick` once in every round.\n\nOn this site the clock is counted, not waited for: `tick(60)` moves the program's clock on by a 60th of a second at once. So a run of 120 frames takes only a moment, and it comes out the same in every run. Play shows the frames at the program's own pace, 60 per second.\n","task":"The ball should fall from the top of the window, 3 pixels per frame, at 60 frames per second. Fill in the blanks: the name of the clock's type, and the operator that moves the ball down.\n","kind":"fill","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nball = pygame.image.load(\"ball.png\")\n\ny = 0\nclock = pygame.time.[[Clock]]()\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(ball, (146, y))\n    pygame.display.flip()\n\n    y [[+=]] 3\n    clock.tick(60)\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nball = pygame.image.load(\"ball.png\")\n\ny = 0\nclock = pygame.time.Clock()\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(ball, (146, y))\n    pygame.display.flip()\n\n    y += 3\n    clock.tick(60)\n","hints":["The clock is made with `pygame.time.Clock()`. Down in the window means a bigger y.","`y += 3` adds 3 to y on every frame."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":40,"events":[]},"expectWindow":{"frames":40,"log":"fill (0, 0, 0)\nblit ball.png at (146, 117)","size":[320,240],"title":"pygame window","image":"lessons/windows/350e058a422ea5d1.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":55,"events":[]},"expectWindow":{"frames":55,"log":"fill (0, 0, 0)\nblit ball.png at (146, 162)","size":[320,240],"title":"pygame window","image":"lessons/windows/4d4bf6378fa6531b.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"assets":["ball.png"],"more":[{"task":"Make the robot climb: on the first frame it's at (140, 200), at the bottom of the window, and after each frame it moves 2 pixels up. Use a clock at 60 frames per second.\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (140, 200))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\ny = 200\nclock = pygame.time.Clock()\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (140, y))\n    pygame.display.flip()\n\n    y -= 2\n    clock.tick(60)\n","hints":["Keep the robot's y in a variable that starts at 200, before the main loop, and draw the robot at `(140, y)`.","Up in the window means a smaller y. After `flip`, make y 2 smaller.","Make the clock before the main loop, `clock = pygame.time.Clock()`, and call `clock.tick(60)` at the end of each round."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":50,"events":[]},"expectWindow":{"frames":50,"log":"fill (0, 0, 0)\nblit robot.png at (140, 102)","size":[320,240],"title":"pygame window","image":"lessons/windows/d23a341e3307d2b8.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":80,"events":[]},"expectWindow":{"frames":80,"log":"fill (0, 0, 0)\nblit robot.png at (140, 42)","size":[320,240],"title":"pygame window","image":"lessons/windows/3efb54d6333c923f.png"},"expect":"","hidden":true}],"require":[{"pattern":"\\.tick\\s*\\(","message":"Keep the speed steady with a clock: `clock.tick(60)` in every round."}],"forbid":[],"assets":["robot.png"]},{"task":"Two things move at once. The robot walks right along the bottom of the window, 2 pixels per frame, and a coin falls, 3 pixels per frame. On the first frame the robot is at (0, 200) and the coin at (148, 0). Draw the robot first, then the coin, and use a clock at 60 frames per second.\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\ncoin = pygame.image.load(\"coin.png\")\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (0, 200))\n    window.blit(coin, (148, 0))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\ncoin = pygame.image.load(\"coin.png\")\n\nrobot_x = 0\ncoin_y = 0\nclock = pygame.time.Clock()\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (robot_x, 200))\n    window.blit(coin, (148, coin_y))\n    pygame.display.flip()\n\n    robot_x += 2\n    coin_y += 3\n    clock.tick(60)\n","hints":["Each moving thing needs a variable for the part of its position that changes, such as `robot_x` and `coin_y`.","Draw both at their variables' positions, and after `flip` change both: `robot_x += 2` and `coin_y += 3`.","Then add the clock, as in the lesson."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":45,"events":[]},"expectWindow":{"frames":45,"log":"fill (0, 0, 0)\nblit robot.png at (88, 200)\nblit coin.png at (148, 132)","size":[320,240],"title":"pygame window","image":"lessons/windows/51c92a66ec66e6fe.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":70,"events":[]},"expectWindow":{"frames":70,"log":"fill (0, 0, 0)\nblit robot.png at (138, 200)\nblit coin.png at (148, 207)","size":[320,240],"title":"pygame window","image":"lessons/windows/84a06d232d922467.png"},"expect":"","hidden":true}],"require":[{"pattern":"\\.tick\\s*\\(","message":"Keep the speed steady with a clock: `clock.tick(60)` in every round."}],"forbid":[],"assets":["robot.png","coin.png"]}]}