{"id":845,"date":"2018-07-30T21:15:56","date_gmt":"2018-07-30T19:15:56","guid":{"rendered":"http:\/\/pythonprogramming.altervista.org\/?p=845"},"modified":"2018-08-27T17:43:59","modified_gmt":"2018-08-27T15:43:59","slug":"pygame-zero-lander-by-daniel-pope","status":"publish","type":"post","link":"https:\/\/pythonprogramming.altervista.org\/pygame-zero-lander-by-daniel-pope\/","title":{"rendered":"Pygame zero: Lander by Daniel Pope"},"content":{"rendered":"<h2>The Game<\/h2>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-846\" src=\"http:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2018\/07\/Lander.png\" alt=\"\" width=\"1005\" height=\"637\" srcset=\"https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2018\/07\/Lander.png 1005w, https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2018\/07\/Lander-320x203.png 320w, https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2018\/07\/Lander-768x487.png 768w, https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2018\/07\/Lander-960x608.png 960w\" sizes=\"auto, (max-width: 1005px) 100vw, 1005px\" \/><\/p>\n<p>To see what can be done with Pygame zero, let&#8217;s take a look at an example of a classic game by the eighties ported in Python by Daniel Pope.<\/p>\n<p>I made some little changes in this game that is one of the example of the use of Pygame zero. Take a look at the code and the game itself in the video.<\/p>\n<p>The original code is in the repository of Pygame zero (read the last article about Pygame zero).<\/p>\n<pre class=\"lang:default decode:true \">import pgzrun\r\nimport random\r\nimport math\r\n\r\n\"\"\"\r\nPi Lander\r\n * A basic Lunar Lander style game in Pygame Zero\r\n * Run with 'pgzrun pi_lander.py', control with the LEFT, RIGHT and UP arrow keys\r\n * Author Tim Martin: www.Tim-Martin.co.uk\r\n * Licence: Creative Commons Attribution-ShareAlike 4.0 International\r\n * http:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\r\n\"\"\"\r\n\r\nWIDTH = 1000  # Screen width\r\nHEIGHT = 600  # Screen height\r\n\r\nsound1 = tone.create('A3', 0.01)\r\n\r\n\r\nclass LandingSpotClass:\r\n    \"\"\" Each instance defines a landing spot by where it starts, how big it is and how many points it's worth \"\"\"\r\n    landing_spot_sizes = [\"small\", \"medium\", \"large\"]\r\n\r\n    def __init__(self, starting_step):\r\n        self.starting = starting_step\r\n        random_size = random.choice(LandingSpotClass.landing_spot_sizes)  # And randomly choose size\r\n        if random_size == \"small\":\r\n            self.size = 4\r\n            self.bonus = 8\r\n        elif random_size == \"medium\":\r\n            self.size = 10\r\n            self.bonus = 4\r\n        else:  # Large\r\n            self.size = 20\r\n            self.bonus = 2\r\n\r\n    def get_within_landing_spot(self, step):\r\n        if (step &gt;= self.starting) and (step &lt; self.starting + self.size):\r\n            return True\r\n        return False\r\n\r\n\r\nclass LandscapeClass:\r\n    \"\"\" Stores and generates the landscape, landing spots and star field \"\"\"\r\n    step_size = 3  # Landscape is broken down into steps. Define number of pixels on the x axis per step.\r\n    world_steps = int(WIDTH \/ step_size)  # How many steps can we fit horizontally on the screen\r\n    small_height_change = 3  # Controls how bumpy the landscape is\r\n    large_height_change = 10  # Controls how steep the landscape is\r\n    features = [\"mountain\", \"valley\", \"field\"]  # What features to generate\r\n    n_stars = 30  # How many stars to put in the background\r\n    n_spots = 4  # Max number of landing spots to generate\r\n\r\n    def __init__(self):\r\n        self.world_height = []  # Holds the height of the landscape at each step\r\n        self.star_locations = []  # Holds the x and y location of the stars\r\n        self.landing_spots = []  # Holds the landing spots\r\n\r\n    def get_within_landing_spot(self, step):\r\n        \"\"\" Calculate if a given step is within any of the landing spots \"\"\"\r\n        for spot in self.landing_spots:\r\n            if spot.get_within_landing_spot(step) == True:\r\n                return True\r\n        return False\r\n\r\n    def get_landing_spot_bonus(self, step):\r\n        for spot in self.landing_spots:\r\n            if spot.get_within_landing_spot(step) == True:\r\n                return spot.bonus\r\n        return 0\r\n\r\n    def reset(self):\r\n        \"\"\" Generates a new landscape \"\"\"\r\n        # First: Choose which steps of the landscape will be landing spots\r\n        del self.landing_spots[:]  # Delete any previous LandingSpotClass objects\r\n        next_spot_start = 0\r\n        # Move from left to right adding new landing spots until either\r\n        # n_spots spots have been placed or we run out of space in the world\r\n        while len(self.landing_spots) &lt; LandscapeClass.n_spots and next_spot_start &lt; LandscapeClass.world_steps:\r\n            next_spot_start += random.randint(10, 50)  # Randomly choose location to start landing spot\r\n            new_landing_spot = LandingSpotClass(next_spot_start)  # Make a new landing object at this spot\r\n            self.landing_spots.append(new_landing_spot)  # And store it in our list\r\n            next_spot_start += new_landing_spot.size  # Then take into account its size before choosing the next\r\n        # Second: Randomise the world map\r\n        del self.world_height[:]  # Clear any previous world height data\r\n        feature_steps = 0  # Keep track of how many steps we are into a feature\r\n        self.world_height.append(random.randint(300, 500))  # Start the landscape between 300 and 500 pixels down\r\n        for step in range(1, LandscapeClass.world_steps):\r\n            # If feature_step is zero, we need to choose a new feature and how long it goes on for\r\n            if feature_steps == 0:\r\n                feature_steps = random.randint(25, 75)\r\n                current_feature = random.choice(LandscapeClass.features)\r\n            # Generate the world by setting the range of random numbers, must be flat if in a landing spot\r\n            if self.get_within_landing_spot(step) == True:\r\n                max_up = 0  # Flat\r\n                max_down = 0  # Flat\r\n            elif current_feature == \"mountain\":\r\n                max_up = LandscapeClass.small_height_change\r\n                max_down = -LandscapeClass.large_height_change\r\n            elif current_feature == \"valley\":\r\n                max_up = LandscapeClass.large_height_change\r\n                max_down = -LandscapeClass.small_height_change\r\n            elif current_feature == \"field\":\r\n                max_up = LandscapeClass.small_height_change\r\n                max_down = -LandscapeClass.small_height_change\r\n            # Generate the next piece of the landscape\r\n            current_height = self.world_height[step - 1]\r\n            next_height = current_height + random.randint(max_down, max_up)\r\n            self.world_height.append(next_height)\r\n            feature_steps -= 1\r\n            # Stop mountains getting too high, or valleys too low\r\n            if next_height &gt; 570:\r\n                current_feature = \"mountain\"  # Too low! Force a mountain\r\n            elif next_height &lt; 200:\r\n                current_feature = \"valley\"  # Too high! Force a valley\r\n        # Third: Randomise the star field\r\n        del self.star_locations[:]\r\n        for star in range(0, LandscapeClass.n_stars):\r\n            star_step = random.randint(0, LandscapeClass.world_steps - 1)\r\n            star_x = star_step * LandscapeClass.step_size\r\n            star_y = random.randint(0, self.world_height[star_step])  # Keep the stars above the landscape\r\n            self.star_locations.append((star_x, star_y))\r\n\r\n\r\nclass ShipClass:\r\n    \"\"\" Holds the state of the player's ship and handles movement \"\"\"\r\n    max_fuel = 1000  # How much fuel the player starts with\r\n    booster_power = 0.05  # Power of the ship's thrusters\r\n    rotate_speed = 10  # How fast the ship rotates in degrees per frame\r\n    gravity = [0., 0.01]  # Strength of gravity in the x and y directions\r\n\r\n    def __init__(self):\r\n        \"\"\" Create the variables which will describe the players ship \"\"\"\r\n        self.angle = 0  # The angle the ship is facing 0 - 360 degrees\r\n        self.altitude = 0  # The number of pixels the ship is above the ground\r\n        self.booster = False  # True if the player is firing their booster\r\n        self.fuel = 0  # Amount of fuel remaining\r\n        self.position = [0, 0]  # The x and y coordinates of the players ship\r\n        self.velocity = [0, 0]  # The x and y velocity of the players ship\r\n        self.acceleration = [0, 0]  # The x and y acceleration of the players ship\r\n\r\n    def reset(self):\r\n        \"\"\" Set the ships position, velocity and angle to their new-game values \"\"\"\r\n        self.position = [750., 100.]  # Always start at the same spot\r\n        self.velocity = [-random.random(), random.random()]  # But with some initial speed\r\n        self.acceleration = [0., 0.]  # No initial acceleration (except gravity of course)\r\n        self.angle = random.randint(0, 360)  # And pointing in a random direction\r\n        self.fuel = ShipClass.max_fuel  # Fill up fuel tanks\r\n\r\n    def rotate(self, direction):\r\n        \"\"\" Rotate the players ship and keep the angle within the range 0 - 360 degrees \"\"\"\r\n        if direction == \"left\":\r\n            self.angle -= ShipClass.rotate_speed\r\n        elif direction == \"right\":\r\n            self.angle += ShipClass.rotate_speed\r\n        if self.angle &gt; 360:  # Remember than adding or subtracting 360 degrees does not change the angle\r\n            self.angle -= 360\r\n        elif self.angle &lt; 0:\r\n            self.angle += 360\r\n\r\n    def booster_on(self):\r\n        \"\"\" When booster is firing we accelerate in the opposite direction, 180 degrees, from the way the ship is facing \"\"\"\r\n        sound1.play()\r\n        self.booster = True\r\n        self.acceleration[0] = ShipClass.booster_power * math.sin(math.radians(self.angle + 180))\r\n        self.acceleration[1] = ShipClass.booster_power * math.cos(math.radians(self.angle + 180))\r\n        self.fuel -= 2\r\n\r\n    def booster_off(self):\r\n        \"\"\" When the booster is not firing we do not accelerate \"\"\"\r\n        self.booster = False\r\n        self.acceleration[0] = 0.\r\n        self.acceleration[1] = 0.\r\n\r\n    def update_physics(self):\r\n        \"\"\" Update ship physics in X and Y, apply acceleration (and gravity) to the velocity and velocity to the position \"\"\"\r\n        for axis in range(0, 2):\r\n            self.velocity[axis] += ShipClass.gravity[axis]\r\n            self.velocity[axis] += self.acceleration[axis]\r\n            self.position[axis] += self.velocity[axis]\r\n        # Update player altitude. Note that (LanscapeClass.step_size * 3) is the length of the ship's legs\r\n        ship_step = int(self.position[0] \/ LandscapeClass.step_size)\r\n        if ship_step &lt; LandscapeClass.world_steps:\r\n            self.altitude = game.landscape.world_height[ship_step] - self.position[1] - (LandscapeClass.step_size * 3)\r\n\r\n    def get_out_of_bounds(self):\r\n        \"\"\" Check if the player has hit the ground or gone off the sides \"\"\"\r\n        if self.altitude &lt;= 0 or self.position[0] &lt;= 0 or self.position[0] &gt;= WIDTH:\r\n            return True\r\n        return False\r\n\r\n\r\nclass GameClass:\r\n    \"\"\" Holds main game data, including the ship and landscape objects. Checks for game-over \"\"\"\r\n\r\n    def __init__(self):\r\n        self.time = 0.  # Time spent playing in seconds\r\n        self.score = 0  # Player's score\r\n        self.game_speed = 30  # How fast the game should run in frames per second\r\n        self.time_elapsed = 0.  # Time since the last frame was changed\r\n        self.blink = True  # True if blinking text is to be shown\r\n        self.n_frames = 0  # Number of frames processed\r\n        self.game_on = False  # True if the game is being played\r\n        self.game_message = \"PI   LANDER\\nPRESS SPACE TO START\"  # Start of game message\r\n        self.ship = ShipClass()  # Make a object of the ShipClass type\r\n        self.landscape = LandscapeClass()\r\n        self.reset()  # Start the game with a fresh landscape and ship\r\n\r\n    def reset(self):\r\n        self.time = 0.\r\n        self.ship.reset()\r\n        self.landscape.reset()\r\n\r\n    def check_game_over(self):\r\n        \"\"\" Check if the game is over and update the game state if so \"\"\"\r\n        if self.ship.get_out_of_bounds() == False:\r\n            return  # Game is not over\r\n        self.game_on = False  # Game has finished. But did we win or loose?\r\n        # Check if the player looses. This is if the ship's angle is &gt; 20 degrees\r\n        # the ship is not over a landing site, is moving too fast or is off the side of the screen\r\n        ship_step = int(self.ship.position[0] \/ LandscapeClass.step_size)\r\n        if self.ship.position[0] &lt;= 0 \\\r\n           or self.ship.position[0] &gt;= WIDTH \\\r\n           or self.landscape.get_within_landing_spot(ship_step) == False \\\r\n           or abs(self.ship.velocity[0]) &gt; .5 \\\r\n           or abs(self.ship.velocity[1]) &gt; .5 \\\r\n           or (self.ship.angle &gt; 20 and self.ship.angle &lt; 340):\r\n            self.game_message = \"YOU JUST DESTROYED A 100 MEGABUCK LANDER\\n\\nLOOSE 250 POINTS\\n\\nPRESS SPACE TO RESTART\"\r\n            self.score -= 250\r\n        else:  # If the player has won! Update their score based on the amount of remaining fuel and the landing bonus\r\n            points = self.ship.fuel \/ 10\r\n            points *= self.landscape.get_landing_spot_bonus(ship_step)\r\n            self.score += points\r\n            self.game_message = \"CONGRATULATIONS\\nTHAT WAS A GREAT LANDING!\\n\\n\" + str(round(points)) + \" POINTS\\n\\nPRESS SPACE TO RESTART\"\r\n\r\n\r\n# Create the game object\r\ngame = GameClass()\r\n\r\n\r\ndef draw():\r\n    \"\"\"\r\n    Draw the game window on the screen in the following order:\r\n    start message, mountain range, bonus points, stars, statistics, player's ship\r\n    \"\"\"\r\n    screen.fill(\"darkblue\")\r\n    size = LandscapeClass.step_size\r\n\r\n    if game.game_on == False:\r\n        screen.draw.text(game.game_message, center=(WIDTH \/ 2, HEIGHT \/ 5), align=\"center\")\r\n\r\n    # Get the x and y coordinates of each step of the landscape and draw it as a straight line\r\n    for step in range(0, game.landscape.world_steps - 1):\r\n        x_start = size * step\r\n        x_end = size * (step + 1)\r\n        y_start = game.landscape.world_height[step]\r\n        y_end = game.landscape.world_height[step + 1]\r\n        screen.draw.line((x_start, y_start), (x_end, y_end), \"white\")\r\n        # Every second we flash the landing spots with a thicker line by drawing a narrow rectangle\r\n        if (game.blink == True or game.game_on == False) and game.landscape.get_within_landing_spot(step) == True:\r\n            screen.draw.filled_rect(Rect(x_start - size, y_start - 3, size, 4), \"gold\")\r\n\r\n    # Draw the bonus point notifier\r\n    if game.blink == True or game.game_on == False:\r\n        for spot in game.landscape.landing_spots:\r\n            x_text = spot.starting * size\r\n            y_text = game.landscape.world_height[spot.starting] + 10  # The extra 10 pixels puts the text below the landscape\r\n            screen.draw.text(str(spot.bonus) + \"x\", (x_text, y_text), color=\"white\")\r\n\r\n    # Draw the stars\r\n    for star in game.landscape.star_locations:\r\n        screen.draw.line(star, star, \"white\")\r\n\r\n    # Draw the stats\r\n    screen.draw.text(\"SCORE: \" + str(round(game.score)), (10, 10), color=\"white\", background=\"black\")\r\n    screen.draw.text(\"TIME: \" + str(round(game.time)), (10, 25), color=\"white\", background=\"black\")\r\n    screen.draw.text(\"FUEL: \" + str(game.ship.fuel), (10, 40), color=\"white\", background=\"black\")\r\n    screen.draw.text(\"ALTITUDE: \" + str(round(game.ship.altitude)), (WIDTH - 230, 10), color=\"white\", background=\"black\")\r\n    screen.draw.text(\"HORIZONTAL SPEED: {0:.2f}\".format(game.ship.velocity[0]), (WIDTH - 230, 25), color=\"white\", background=\"black\")\r\n    screen.draw.text(\"VERTICAL SPEED: {0:.2f}\".format(-game.ship.velocity[1]), (WIDTH - 230, 40), color=\"white\", background=\"black\")\r\n\r\n    screen.draw.filled_circle(game.ship.position, size * 2, \"yellow\")  # Draw the player\r\n    screen.draw.circle(game.ship.position, size * 2, \"orange\")  # Draw the player\r\n    screen.draw.filled_circle(game.ship.position, size * 1, \"orange\")\r\n    # Use sin and cosine functions to draw the ship legs and booster at the correct angle\r\n    # Requires the values in radians (0 to 2*pi) rather than in degrees (0 to 360)\r\n    sin_angle = math.sin(math.radians(game.ship.angle - 45))  # Legs are drawn 45 degrees either side of the ship's angle\r\n    cos_angle = math.cos(math.radians(game.ship.angle - 45))\r\n    screen.draw.line(game.ship.position, (game.ship.position[0] + (sin_angle * size * 4), game.ship.position[1] + (cos_angle * size * 4)), \"red\")\r\n    sin_angle = math.sin(math.radians(game.ship.angle + 45))\r\n    cos_angle = math.cos(math.radians(game.ship.angle + 45))\r\n    screen.draw.line(game.ship.position, (game.ship.position[0] + (sin_angle * size * 4), game.ship.position[1] + (cos_angle * size * 4)), \"red\")\r\n    if game.ship.booster == True:\r\n        sin_angle = math.sin(math.radians(game.ship.angle))  # Booster is drawn at the same angle as the ship, just under it\r\n        cos_angle = math.cos(math.radians(game.ship.angle))\r\n        screen.draw.filled_circle((game.ship.position[0] + (sin_angle * size * 3), game.ship.position[1] + (cos_angle * size * 3)), size, \"orange\")\r\n\r\n\r\ndef update(detlatime):\r\n    \"\"\" Updates the game physics 30 times every second  \"\"\"\r\n    game.time_elapsed += detlatime\r\n    if game.time_elapsed &lt; 1. \/ game.game_speed:\r\n        return  # A 30th of a second has not passed yet\r\n    game.time_elapsed -= 1. \/ game.game_speed\r\n\r\n    # New frame - do all the simulations\r\n    game.n_frames += 1\r\n    if game.n_frames % game.game_speed == 0:  # If n_frames is an exact multiple of the game FPS: so once per second\r\n        game.blink = not game.blink  # Invert blink so True becomes False or False becomes True\r\n\r\n    # Start the game if the player presses space when the game is not on\r\n    if keyboard.space and game.game_on == False:\r\n        game.game_on = True\r\n        game.reset()\r\n    elif game.game_on == False:\r\n        return\r\n\r\n    # If the game is on, update the movement and the physics\r\n    if keyboard.left:  # Change space ship rotation\r\n        game.ship.rotate(\"left\")\r\n    elif keyboard.right:\r\n        game.ship.rotate(\"right\")\r\n\r\n    if keyboard.up and game.ship.fuel &gt; 0:  # Fire boosters if the player has enough fuel\r\n        game.ship.booster_on()\r\n    else:\r\n        game.ship.booster_off()\r\n\r\n    game.time += detlatime\r\n    game.ship.update_physics()\r\n    game.check_game_over()\r\n\r\n\r\npgzrun.go()\r\n<\/pre>\n<h2>Videogame<\/h2>\n<p><iframe loading=\"lazy\" width=\"100%\" height=\"400\" src=\"https:\/\/www.youtube.com\/embed\/QisUXvxPxKo\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen><\/iframe><\/p>\n<h2>Video with music and new sounds<\/h2>\n<p><iframe loading=\"lazy\" width=\"100%\" height=\"400\" src=\"https:\/\/www.youtube.com\/embed\/mRizXqPN5oM\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen><\/iframe><\/p>\n\t<script>\r\nvar title = \"Pygame zero\";\r\n\t\tvar links = [\r\n[\"https:\/\/pythonprogramming.altervista.org\/pong-v-1-0-pygame-example\/\",\"Pong v.1.0 (mouse) - Arkanoid beta\"],\r\n['https:\/\/pythonprogramming.altervista.org\/python-making-a-video-game\/', 'Example 1: intro'],\r\n['https:\/\/pythonprogramming.altervista.org\/pygame-zero-another-example\/', 'Example 2: a simple interaction'],\r\n['https:\/\/pythonprogramming.altervista.org\/pygame-zero-3-some-more-funny-games\/', 'Example 3: a simple game'],\r\n['https:\/\/pythonprogramming.altervista.org\/pygame-zero-4-catch-my-fall\/', 'Example 4: Alien Fall'],\r\n['https:\/\/pythonprogramming.altervista.org\/pygame-zero-5-improving-graphic-and-adding-sounds\/', 'Example 5: Alien Fall (2) - graphic and sounds'],\r\n['https:\/\/pythonprogramming.altervista.org\/pygame-zero-lander-by-daniel-pope\/', 'Lander: game 1'],\r\n['https:\/\/pythonprogramming.altervista.org\/pygame-zero-games-examples\/', 'Repository pygame and examples']\r\n];\r\n<\/script>\r\n<script>\r\n\t\r\nif (typeof next2 != \"undefined\"){let next2 = 0;}\r\n\t\r\nnext2 = 0;\r\n\thtml = \"\";\/\/<b style='color:coral;font-size:1.2em'>Other posts about \" + title + \"<\/b><br>\";\r\nfor (address of links) \r\n{\r\n\r\n\tif (next2 == 1){\r\n\t\thtml += \"<div style='background:coral'>\";\r\n\t\thtml += \"Next link => <a href='\" + address[0] + \"'>\" + address[1] + \"<\/a>\";\r\n\t\thtml += \"<\/div><br>\";\r\n\t\tnext2 = 0;\r\n\t}\r\n\tif (address[0] == document.URL) {\r\n\t\tnext2 = 1;\r\n\t}\r\n}\r\n\r\nif (typeof next != \"undefined\") {let next = 0;}\r\nif (typeof addressStart != \"undefined\") {let addressStart = \"\";}\r\nnext = 0;\r\naddressStart = \"<a href='\";\r\nfor (address of links) {\r\n\tif (next == 1){\r\n\t\thtml += \">>>\" + addressStart + address[0] + \"'>\" + address[1] + \"<\/a><br>\";\r\n\t\tnext = 0;\r\n\t}\r\n\telse if (addressStart + address[0] != document.URL)\r\n\t{\r\n\t\thtml += addressStart + address[0] + \"'>\" + address[1] + \"<\/a><br>\";\r\n\t}\r\n\telse\r\n\t{\r\n\t\tnext = 1;\r\n\t\tnext_address = address[0]\r\n\t\tnext_title = address[1]\r\n\t\thtml += \"<span style='color:gray'>\" + address[1] + \"<\/span><br>\";\r\n\t}\r\n\r\n}\r\n\r\n\thtml += `<span style=\"font-size:8px\">Powered by <a href=\"https:\/\/pythonprogramming.altervista.org\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2673\" src=\"https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2019\/06\/altervista2.png\" alt=\"\" width=\"70\" height=\"25\" srcset=\"https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2019\/06\/altervista2.png 156w, https:\/\/pythonprogramming.altervista.org\/wp-content\/uploads\/2019\/06\/altervista2-150x56.png 150w\" sizes=\"auto, (max-width: 70px) 100vw, 70px\" \/>pythonprogramming.altervista.org<\/a><\/span>`\r\n\thtml = \"<div style='background:yellow'>\" + html + \"<\/div>\";\r\n\tdocument.write(html)\r\n<\/script>\n","protected":false},"excerpt":{"rendered":"Pygame zero: the Lander videogame.\n<a class=\"moretag\" href=\"https:\/\/pythonprogramming.altervista.org\/pygame-zero-lander-by-daniel-pope\/\"> [...]<\/a>","protected":false},"author":1,"featured_media":846,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[154,191,198],"tags":[137,158,200,194,192,4,199],"class_list":["post-845","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-games","category-pygame","category-pygame-zero","tag-game","tag-games","tag-lander","tag-pygame","tag-pygame-zero","tag-python","tag-videogame"],"avopt_banners_inside_post":true,"avopt_banners_on_page":true,"av_copy_from":"","av_sharing_message":"","av_sharing_allowed":false,"av_sharing_on":{"fb":[],"tw":[]},"av_allow_affiliate_banner":false,"av_allow_affiliate_multi_banner":false,"av_show_affiliation_buy_button":false,"av_post_rating":true,"av_have_post_rating_value":false,"av_is_artificial_intelligence_content":false,"_links":{"self":[{"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/posts\/845","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/comments?post=845"}],"version-history":[{"count":6,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/posts\/845\/revisions"}],"predecessor-version":[{"id":1319,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/posts\/845\/revisions\/1319"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/media\/846"}],"wp:attachment":[{"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/media?parent=845"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/categories?post=845"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pythonprogramming.altervista.org\/wp-json\/wp\/v2\/tags?post=845"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}