{"id":"pygame-images","slug":"images","title":"Images and coordinates","text":"Most of what a game shows is images. This is `robot.png`, one of the images on this site:\n\n```asset robot.png\n40x40\n```\n\n`pygame.image.load(\"robot.png\")` reads an image file and returns it as a **surface**, the same kind of object as the window: a rectangle of pixels. pygame looks for the file next to your program, so on your own computer you keep the two together. On this site, the images that an example or a challenge uses are there already. Load each image once, before the main loop: reading a file takes time, and the image stays the same.\n\nTo draw an image, you give the window's `blit` method the image and a point: `window.blit(robot, (60, 90))` puts the robot so that its top-left corner is at (60, 90). (**Blit** is old graphics slang for copying a block of pixels onto another.)\n\n```python\nimport 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, (60, 90))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/231662ea8454632e.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":30,\"log\":\"fill (0, 0, 0)\\nblit robot.png at (60, 90)\",\"ended\":\"closed\",\"code\":\"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, (60, 90))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":30,\"events\":[]},\"assets\":[\"robot.png\"]}\n```\n\nAs text, this window is:\n\n```text\nfill (0, 0, 0)\nblit robot.png at (60, 90)\n```\n\n### Coordinates\n\nA point in the window is a pair (x, y) of pixel counts, measured from the window's **top-left corner**, which is (0, 0). x says how far right of the left edge the point is, and y how far below the top edge: (60, 90) is 60 pixels in from the left and 90 pixels down. On a graph in math class, y grows upward, but in a window it grows **downward**: a bigger y is lower in the window. Most graphics libraries count this way, so you'll meet it again.\n\nThe robot is 40 by 40 pixels, so at (60, 90) it covers x from 60 to 99 and y from 90 to 129. To put it in the window's bottom-right corner, its top-left corner goes to (320 - 40, 240 - 40), which is (280, 200). At (320, 240) it would be just outside the window, and you wouldn't see it at all.\n\nAn image you've loaded can be drawn as many times as you like. Here is the robot between two coins, which are 24 by 24 pixels:\n\n```asset coin.png\n24x24\n```\n\n```python\nimport 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, (140, 100))\n    window.blit(coin, (80, 108))\n    window.blit(coin, (216, 108))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/9e1c6dd51e221340.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":30,\"log\":\"fill (0, 0, 0)\\nblit robot.png at (140, 100)\\nblit coin.png at (80, 108)\\nblit coin.png at (216, 108)\",\"ended\":\"closed\",\"code\":\"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, (140, 100))\\n    window.blit(coin, (80, 108))\\n    window.blit(coin, (216, 108))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":30,\"events\":[]},\"assets\":[\"robot.png\",\"coin.png\"]}\n```\n\n### Drawing order\n\nDrawing in the window works like painting: what you draw later covers what's already there. That's why `fill` comes first in each frame. It paints over the previous frame, and then the images go on top. Here the fill comes last by mistake, and it paints over the robot:\n\n```python\nimport 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.blit(robot, (60, 90))\n    window.fill((0, 0, 0))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/f8919e417f3af6aa.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":30,\"log\":\"fill (0, 0, 0)\",\"ended\":\"closed\",\"code\":\"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.blit(robot, (60, 90))\\n    window.fill((0, 0, 0))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":30,\"events\":[]},\"assets\":[\"robot.png\",\"coin.png\"]}\n```\n\nThe window is all black, and its text is only `fill (0, 0, 0)`: like the picture, the text starts over at each fill that covers the whole window. When images overlap, the one drawn last is in front. The order is part of the window as text, so the checks compare it too, and when a task has several things to draw, it says in which order.\n","task":"Fill in the blanks so the program loads the image `monster.png` and draws it with its top-left corner at (200, 30).\n","kind":"fill","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nmonster = pygame.image.[[load]](\"monster.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]](monster, (200, 30))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nmonster = pygame.image.load(\"monster.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(monster, (200, 30))\n    pygame.display.flip()\n","hints":["The first blank reads the image file. The second draws the image in the window.","`pygame.image.load` reads the file, and the window's method `blit` draws it."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":10,"events":[]},"expectWindow":{"frames":10,"log":"fill (0, 0, 0)\nblit monster.png at (200, 30)","size":[320,240],"title":"pygame window","image":"lessons/windows/3a69709d06202ab8.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":3,"events":[]},"expectWindow":{"frames":3,"log":"fill (0, 0, 0)\nblit monster.png at (200, 30)","size":[320,240],"title":"pygame window","image":"lessons/windows/3a69709d06202ab8.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"assets":["monster.png"],"more":[{"task":"Draw three images in a black 320 x 240 window: the robot in the bottom-left corner, the monster in the bottom-right corner and a coin in the top-right corner. Each image must be completely inside the window and touch the corner's two edges. The robot and the monster are 40 x 40 pixels, the coin 24 x 24. Draw them in this order: the robot, the monster, the coin.\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\nmonster = pygame.image.load(\"monster.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    # Draw the robot, the monster and the coin here.\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\nmonster = pygame.image.load(\"monster.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(monster, (280, 200))\n    window.blit(coin, (296, 0))\n    pygame.display.flip()\n","hints":["The point you give `blit` is where the image's top-left corner goes. In the bottom-left corner, x is 0, and y is the window's height minus the image's height.","The robot goes to (0, 240 - 40). The monster's x is 320 - 40, and the coin's x is 320 - 24 with y 0.","Three `blit` calls, in the order the task gives: robot, monster, coin."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":10,"events":[]},"expectWindow":{"frames":10,"log":"fill (0, 0, 0)\nblit robot.png at (0, 200)\nblit monster.png at (280, 200)\nblit coin.png at (296, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/ee1f94b30e4f396e.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":4,"events":[]},"expectWindow":{"frames":4,"log":"fill (0, 0, 0)\nblit robot.png at (0, 200)\nblit monster.png at (280, 200)\nblit coin.png at (296, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/ee1f94b30e4f396e.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"assets":["robot.png","monster.png","coin.png"]},{"task":"A coin should lie on top of a box in the middle of a dark gray window, but the window shows only gray. Fix the order of the drawing: first fill the window, then draw the box, and the coin last, so that it's in front of the box.\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nbox = pygame.image.load(\"box.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.blit(coin, (148, 108))\n    window.blit(box, (140, 100))\n    window.fill((40, 40, 40))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nbox = pygame.image.load(\"box.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((40, 40, 40))\n    window.blit(box, (140, 100))\n    window.blit(coin, (148, 108))\n    pygame.display.flip()\n","hints":["What's drawn later covers what's already there. Here the fill comes last, so it covers everything.","Move the `fill` line to the top of the drawing. Then swap the two `blit` lines, so the box is drawn before the coin."],"tests":[{"name":"Test 1","stdin":"","window":{"frames":10,"events":[]},"expectWindow":{"frames":10,"log":"fill (40, 40, 40)\nblit box.png at (140, 100)\nblit coin.png at (148, 108)","size":[320,240],"title":"pygame window","image":"lessons/windows/3dda31cc595f8918.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":6,"events":[]},"expectWindow":{"frames":6,"log":"fill (40, 40, 40)\nblit box.png at (140, 100)\nblit coin.png at (148, 108)","size":[320,240],"title":"pygame window","image":"lessons/windows/3dda31cc595f8918.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"assets":["box.png","coin.png"]}]}