Как сделать платформер на python pygame

от admin

Создание 2D платформера на Python

Для многих Python — это язык для написания веб проектов, машинного обучения или для анализа данных. На самом деле он более функционален и в этой статье мы вам это докажем.

Для реализации игр на Питон мы можем выбрать одну из нескольких библиотек. Можно работать с: Kivy, Tkinter, PyQt или же с любой другой библиотекой, что обеспечивает построение графического интерфейса через Python. Таких библиотек много, но мы возьмем библиотеку PyGame , которая даже своим названием говорит о её предназначении.

PyGame появился в 2000 году. С тех пор на его основе было сделано много интересных проектов . К сожалению, PyGame не универсален и разработка на нём ведется лишь под Андроид устройства.

Настройка проекта

Перед использованием PyGame его нужно установить через терминал. Прописываем команду:

Для создания базового окна игры, необходимо лишь импортировать библиотеку, инициализировать главный объект, указать размеры, а также название окна и создать основной цикл, что должен вызываться постоянно и тем самым проект будет запущен и работать все время.

Сюда же дописываем отслеживание действий пользователя. Если он закроет окно, то мы будем останавливать программу.

Создание платформера

Для создания платформера потребуется написать куда больше строк кода. Мы прикрепляем весь код проекта ниже. В коде есть комментарии для лучшего понимания:

Также для игры вам потребуются картинки игрока и платформы. Вы можете их скачать ниже.

(фото на задний фон)

Видео на эту тему

Также вы можете просмотреть детальное видео по разработке 2D платформера на Python + PyGame:

Дополнительный курс

На нашем сайте также есть углубленный курс по изучению языка Питон . В ходе огромной программы вы изучите не только язык Питон, но также научитесь создавать веб сайты за счёт веб технологий и фреймворка Джанго. За курс вы изучите массу нового и к концу программы будете уметь работать с языком Питон, создавать на нём полноценные ПК приложения на основе библиотеки Kivy, а также создавать веб сайты на основе библиотеки Джанго.

Більше цікавих новин

Создание Java программы с дизайном! Изучение библиотеки JavaFxСоздание Java программы с дизайном! Изучение библиотеки JavaFx
Эти проекты обречены на успех: самые свежие идеи для программистовЭти проекты обречены на успех: самые свежие идеи для программистов
10 инструментов для облегчения работы веб-разработчика10 инструментов для облегчения работы веб-разработчика
Программа на Python для управления компьютером / PyAutoGuiПрограмма на Python для управления компьютером / PyAutoGui

Pygame Platformer – Game Development

Ezoic report this ad Ezoic report this ad Ezoic report this ad

This article covers the game development of a Platformer game in Pygame.

Welcome to the Pygame Platformer Game Development! In this section, we’ll be building a 2D Platformer game using the Python game library, Pygame. Fair warning to all our readers, this article is primarily targeted towards people already somewhat familiar with Pygame.

We will only be skimming over basic pygame concepts, reserving most of our time for the more advanced concepts. If you’re quick and intuitive you’ll probably be able to follow along, but I still recommend you read our Pygame Tutorial (aimed towards absolute beginners) first.

This article will cover some advanced concepts (listed below). Due to the sheer size of the code (300+ lines) and the explanation required, we’ll be splitting the game across several articles, each tackling a certain number of problems and features.

About the Game

Game programming with Pygame

A sneak peek at the final version game we’ll be building

Chances are you’ve played one of these platformer games before. It’s a simple game where you keep moving your character upwards by jumping on the available platforms. If you miss a platform and fall to your doom, it’s game over. You earn a point for every platform you cross. There’s no limit to the game, ending only when you fall and die (or get bored and quit).

Included Concepts
  1. Collision Detection
  2. Player movement (realistic sideways movement)
  3. Jump mechanics
  4. Gravity and Friction
  5. Random Level Generation
  6. Warpable screen movement
  7. Scrolling the screen (creating an infinite height)
  8. Creating a Score counter
  9. “Game Over” Mechanic
  10. Random Platform movement

Part 1 – Setting the Foundation

In this article we’ll set the foundation for our game. Creating our player sprite and setting up some movement controls.

Initialization and Constants

The above code is all pre-game related. You can see us importing the pygame module(s), calling pygame.init() to initialize pygame, setting up several constants such as screen height and width etc. We also set up a clock in pygame, which we’ll use later to control the Frames displayed per second.

Next we’ve set up the display screen using the WIDTH and HEIGHT variables and given the display window the name “Game”.

You’ll have noticed the constants ACC and FRIC and the variable called vec . These, we’ll be using later on in the article to create realistic movement and implement gravity.

Pygame game programming

Above is an image of our current progress. A 450 by 500 pixel display screen. We have no objects made, so it’s a blank screen with the default black color.

Player and Platform Classes

In this game, we’re going to have two different types of entities. The player who we will be controlling and the platforms on which we’ll be jumping. We’re going to create two different classes for each one of these entities.

If you haven’t been using classes until now, this is a good time to start. This approach allow us to easily duplicate and access the objects we’re going to be creating. You’ll realize this once we begin creating many platforms. For now we’re just making one.

Most of this should only require basic Pygame knowledge. We create surface objects for each class with a fixed size. We give each of them a color using the fill() function (RGB format). Finally, we create a rect object from the surface object using the get_rect() method on the surface object.

The center = (10, 420) and center = (WIDTH/2, HEIGHT — 10) parameters we passed are used to define the starting position of the objects when they are drawn to screen. Remember, top left hand corner is the origin point with the co-ordinates (0, 0) .

Finally, we create two objects, PT1 (stands for platform 1) and P1 (stands for Player 1). These names are completely arbitrary of course, and you can change them to whatever you want.

We have no images to show our progress so far, because the screen still shows the same black screen as before. This is because we haven’t drawn any of the objects we created above to the display screen.

Sprites Groups + Game Loop

In this section we’ll work on creating the game loop as well as introducing sprite groups.

For now we’ll go with a generic “ all_sprites “, Sprite group and if the need arises, we’ll create more later. We’ve proceeded to add both the platform and the player to this sprite group. This enables us to easily access all these sprites at the same time as you’ll see later.

We’ve setup the game loop to be able look for the QUIT event and shut down Pygame accordingly. Besides this, we use the fill() function on the displaysurface to refresh the screen with each iteration.

Next up in the game loop, we iterate through the all_sprites() group, drawing all of them to the screen. Without sprite groups, we would have to individually draw each one of them to screen.

Finally, we use the update() function to push all the changes to the screen and update it. The tick() function, used on the Clock() object we created earlier limits the Game loop to refreshing 60 times per second.

Pygame game programming objects

This is what our current progress in our Platformer game has resulted in. However, we can’t interact with or control our player in any way yet. We’ll be dealing with this in the next section.

Implementing Movement

Now, this is a fairly complex part that uses concepts from Kinematics (Physics) and the equations of motion to bring in the concept of acceleration and deceleration. Furthermore, we’ve also added the element of friction, else your speed would be sending you flying all over the place.

Due to the complexity, we’ll study this in shorter pieces. First we’re going to add the following three lines to the Player class ( init function ).

It’s not as complicated as it looks. vec is simply used to create variables with two dimensions. If you go back and look at the start where we initialized it, you’ll see that it’s creating vectors. If you’re good with maths and physics, you’ll understand this quickly.

Creating two dimensional vectors allows us to keep things simpler. Remember, velocity and acceleration are vector quantities. There is horizontal acceleration and also vertical acceleration. Same goes for velocity.

The first parameters represents acceleration/velocity along the X axis and the second is for the Y axis . Notice that we’ve removed the center parameter. This is because we’ve shifted control of the Player’s position to the self.pos variable. Next up is the move() function that will allow us to control our player.

This first part is pretty simple. The function first re-sets the value of the acceleration to 0, then checks for key presses. If the left key has been pressed, it will update the acceleration with a negative value (acceleration in the opposite direction). If the right key has been pressed, acceleration will have a positive value.

This part is a bit complicated, so you can simply copy it if you want. You can see an equation of motion there on the third line. We also use friction to to decrease the value of the velocity. Without friction, our player would not de-accelerate. You can tweak the value of the FRIC variable to adjust the movement.

These two if statements are a clever trick that allows “screen warping”. In other words, you can “go through” the left side of the screen, and pop up on the right side. Of course, if you don’t want this feature, you can re-purpose the two if statements and wrap them around the whole code to ensure you don’t move off screen.

The last line updates the rect() object of the Player with the new position that it has gained after being moved.

If you don’t want to add these concepts of Friction and acceleration, you can just go with the regular movement system that most games use. You can find it anywhere online or at our own Pygame Tutorial here.

We’ve created the move function, but it’s useful until we’ve actually connected it to the rest of our code. Simply add the following line into your game loop.

This will cause the move() function of Player 1 to be called in every iteration of the game loop.

Below is a short video, show casing what we’ve accomplished so far.

If you have any trouble with some of the code above, I recommend you try running it piece by piece and experimenting with it on your own. Leave out certain lines to discover their effect on the game. Game development in Pygame is a skill learnt best when you’re the one tinkering with the Platformer (or any game) code yourself.

Click on the button below to head over to the next Part in this series of Game Development with Pygame Platformer. The complete code for this article is also available in Part 2.

Interested in taking things to the next level? Check out this article on Game Development Books to become a real Game Developer!

This marks the end of the Pygame Platformer Game Development article. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the article material can be asked in the comments section below.

Build a 2D Platform Game with PyGame and Replit

In a previous tutorial we introduced graphical game development with PyGame, covering how to develop a 2D game with animated sprites and user interaction. In this tutorial, we'll go a step further and create a 2D platformer, where you can have an alien walk and jump around a room full of boxes. The previous PyGame tutorial is not a prerequisite for trying this one.

We're going to focus on basic animation and movement to create a solid base from which you can continue on to build an entire platform game, complete with enemies, power-ups and multiple levels.

Getting Started​

Create a new repl and select "PyGame" from the language dropdown.

You'll see "Python3 with PyGame" displayed in the default console and a separate pane in the Replit IDE where you will be able to see and interact with the game you will create.

Before we start writing code, we're going to need a few sprites, which we've made available here. Extract this ZIP file and add the files inside to your repl using the upload file function. You can select multiple files to upload at once. Your repl's file pane should now look like this:

In this tutorial, we will be gradually building up the main.py file, adding code in different parts of the file as we go along. Each code snippets will contain some existing code to give you an idea of where in the file the new additions should be placed. The line # . will be used to represent existing code that has been left out for brevity.

Setting up the scaffolding​

We will start with the following code in main.py , which draws a black screen:

At the top of the file, we import pygame . Following that, we set the width and height of the screen in pixels, and the background color. This last value is an RGB tuple, and will make our background black. To use a white background instead, we would write (255, 255, 255) .

Then, in the main method, we initiate PyGame, create both the screen and the clock, and start the game loop, which is this code:

The game loop is where everything happens. Because our game runs in real time, our code needs to constantly poll for the user's keystrokes and mouse movements, and constantly redraw the screen in response to those keystrokes and mouse movements, and to other events in the game. We achieve this with an infinite while loop. PyGame uses the final clock.tick(60) line in this loop to adjust the game's framerate in line with how long each iteration of the loop takes, in order to keep the game running smoothly.

Now let's draw something on this black screen. Our game is going to have two sprites: an alien, which will be the player, and a box. To avoid code duplication, let's create a Sprite parent class before we create either of those. This class will inherit from the pygame.sprite.Sprite class, which gives us useful methods for collision detection – this will become important later on.

As this class will be the parent for all other objects in our game, we're keeping it quite simple. It has three methods:

  • __init__ , which will create the sprite with a given image and a PyGame rectangle based on that image. This rectangle will initially be placed at the position specified by startx and starty . The sprite's rectangle is what PyGame will use for sprite movement and collision detection.
  • update , which we'll use in child classes to handle events, such as key presses, gravity and collisions.
  • draw , which we use to draw the sprite. We do this by blitting it onto the screen.

Now we can create our Player and Box objects as child classes of Sprite :

We'll add more code to the player later, but first let's draw these sprites on the screen.

Drawing the sprites​

Let's go back to our main function and create our sprites. We'll start with the player:

Then we need to put boxes under the player's feet. As we will be placing multiple sprites, we'll create a PyGame sprite group to put them in.

Our box sprites are 70 pixels wide, and we need to span over the screen width of 400 pixels. We can do this in a for loop using Python's range :

Now we need to go back to the game loop and add some code to make things happen. First, we'll have PyGame put new events on the event queue, and then we'll call the player's update function. This function will handle the events generated by pygame.event.pump() .

For a more complex game, we would want to loop through a number of sprites and call each one's update method, but for now just doing this with the player is sufficient. Our boxes won't have any dynamic behavior, so there's no need to call their update methods.

In contrast to update , we need all our sprites to draw themselves. After drawing the background, we'll add a call to the player's draw method. To draw the boxes, we can call PyGame's Group.draw on our boxes group.

Our game loop is now set up to update and draw every sprite in the game in each cycle of the game loop. If you run the game now, you should see both the player and the line of boxes on the screen.

Next, we're going to add some user interaction.

Making the Player Walk​

Let's return to the Player object and make it mobile. We'll move the player using pygame.Rect.move_ip , which moves a given rectangle by a given vector. This will be wrapped in a move method, to simplify our code. Create this method now:

Now that we have a way to move the player, it's time to add an update method so that this movement can be triggered by key presses. Add an empty update method now:

PyGame provides a couple of different ways to check the state of the keyboard. By default, its event queue collects KEY_DOWN and KEY_UP events when particular keys are pressed and released. Using a KEY_DOWN event to move the player seems like the logical thing to do, but because the event is only triggered in same update loop in which the key is first pressed, this would force us to rapidly tap an arrow key to keep moving in a single direction.

We need a way to move the player whenever an arrow key is held down, not just after it's pressed. So instead of relying on events, we will query the current status of all keyboard keys with pygame.key.get_pressed() :

This method returns a tuple of 0s and 1s showing the pressed status of each key on the keyboard. We can thus detect whether the left or right arrow key is currently pressed by indexing the tuple with PyGame's keyboard constants, like so:

Читать:
Что вешает апач сервер 1с

Run the game. You should now be able to move the player left and right, albeit very slowly. Let's speed things up and reduce our code's reliance on magic numbers at the same time by giving the player a speed variable.

Right now the player glides from side to side, but we have already uploaded images for a walk cycle animation, so let's implement that now. First, we'll add some image loading code to our player's __init__ method:

In this code, we first designate our initial alien image as stand_image . This will allow us to use it for the player when he's standing still. We then load our walking images into a list called walk_cycle , using Python's string formatting to get the correct filename format ( p1_walk01.png -> p1_walk11.png ). We then create self.animation_index , which will record which frame of the walk cycle the player is on, and self.facing_left which will help us to flip the right-facing walking images when the player is walking left.

Now let's implement the actual animation. Create a new method called walk_animation :

Here we're setting the player's current image to the frame of the walk cycle we're currently on. If the player is facing left, we use pygame.transform.flip to horizontally flip his sprite (the last two arguments are for horizontal and vertical flipping, respectively). Then we animate the player by incrementing the animation_index , unless the animation is in its penultimate frame, in which case we return to the start of the animation.

Let's add this to our update method now:

If we're moving left or right, we set self.facing_left appropriately and call self.walk_animation . Otherwise, we set the player's image to self.stand_image .

Run the game now to see the player's walk cycle in motion. After that, it's time to make him jump.

Making the Player Jump​

For our player to be able to jump, we need to implement four things:

  1. Upward motion triggered by the up arrow key.
  2. Gravity, to bring the player back down after reaching the top of his jump.
  3. Collision detection, so the player doesn't fall through the ground.
  4. A jumping animation.

Triggering the jump​

To simply make the player move up, we can just add another elif , like so:

If you try the game now, you should notice a couple of problems with this approach. Besides the lack of gravity, we can only jump straight up, and must release the left and right arrow keys before we may do so. Much of the gameplay in platformers is reliant on the player's ability to jump to the left or right, so this won't do. To fix this, we'll change our last elif to a separate if statement:

We also probably want to be able to jump at a different speed to our walking pace, so let's define another variable and use it.

That's better, but now we really need some gravity!

Adding gravity​

Up until now, we've had only a single operation manipulating our horizontal or vertical speed per update loop. With the addition of gravity, this will change, so we need to restructure our code to calculate our net horizontal and vertical movement before calling move . Let's change the update function like so:

We've added two variables, hsp and vsp , to represent our horizontal speed and vertical speed. Instead of calling move when each key is pressed, we work with these variables throughout the update method and then pass their final values into a single move call at the end.

But wait! It makes sense for horizontal speed to be set to 0 at the start of every update loop, because it is directly controlled by the player's key presses. When the left arrow is held down, the player moves left at a speed of 4 pixels per loop; when the left arrow is released, the player instantly stops. Vertical speed will be less controllable – while pressing the up arrow will initiate a jump, releasing it should not stop the player in mid-air. Therefore, vertical speed must persist between loops.

We can accomplish this by moving the vsp definition into __init__ and making it an instance variable.

Now we can implement gravity. We'll do this by adding a small constant to the player's vertical speed ( vsp ) until it reaches terminal velocity.

Start up the game now, and the player will fall straight down, through the ground and off the screen. Gravity's working, but we need somewhere for the player to land.

Adding collision detection​

Collision detection is a key element of most graphical games. In PyGame, the bulk of collision detection involves checking whether rectangles intersect with each other. Luckily, PyGame provides a number of useful built-ins for doing this, so we won't have to think too much about the internal workings of collisions.

Let's add some collision detection now, near the top of our update method. We'll create a variable called onground and set it to the result of pygame.sprite.spritecollideany() .

This PyGame method takes two arguments: a single sprite and a group of sprites. It returns whether the sprite given as the first argument, i.e. the player, has a collision with any of the sprites in the group given as the second argument, i.e. the boxes. So we'll know that the player is on a box when it returns True .

We can pass the boxes group into the player's update method by making a couple of code changes:

Now that we can tell whether the player is on the ground, we can prevent jumping in mid-air by adding a condition to our jump code:

To stop the player from falling through the ground, we'll add the following code to our gravity implementation:

Adding a jumping animation​

Lastly, we'll use our last alien image ( p1_jump.png ) to give our player a jumping animation. First create self.jump_image in __init__ :

Then create the following Player method:

Our jump animation only has one frame, so the code is much simpler than what we used for our walking animation. To trigger this method when the player is in the air, alter the gravity implementation like so:

Run the game, and you should be able to run and jump! Be careful not to fall off the edge.

Refining the Game​

At this point, we have our game working on a basic level, but it could use some refinements. First, the jumping is quite unresponsive to user input: pressing the up arrow for any length of time results in the same size jump. Second, our collision detection will only prevent the player from falling through the floor, not walking through walls or jumping through the ceiling.

We're going to iterate on our code to fix both of these shortcomings.

Making jumps variable​

It would be nice if the player could control the height of their jump by holding the jump key down for different lengths of time. This is fairly simple to implement – we just need a way to reduce the speed of a jump if the player releases the jump key while the player is still moving up. Add the following code to the player's __init__ method.

Here we've added a prev_key instance variable that will track the state of the keyboard in the previous update loop, and a min_jumpspeed variable, which will be the smallest jump we'll allow the player to do, by just tapping the jump key.

Now let's add variable jumping to the update method, between the code that handles the up arrow key and the code that handles gravity:

The if statement we've just added will evaluate to True if the up arrow key was pressed in the previous loop but is not longer pressed, i.e. it has been released. When that happens, we cut off the player's jump by reducing its speed to the min_jumpspeed . We then set self.prev_key to the current keyboard state in preparation for the next loop.

Try the game now, and you should notice a different height of jump when lightly tap the up arrow key versus when you hold it down. Play around with the value of min_jumpspeed and see what difference it makes.

Refining collision detection​

As mentioned above, the only collision detection we've implemented applies to the ground beneath the player's feet, so he will be able to walk through walls and jump through ceilings. See this for yourself by adding some boxes above and next to the player in the main method.

Another issue that you may have already noticed is that the player sinks into the ground after some jumps – this results from the imprecision of our collision detection.

We're going to fix these problems by making a subtle change to how we deal with collisions with boxes. Rather than deciding that we're on the ground when the player sprite is in collision with a box, we'll check whether the player is 1 pixel above a collision with a box. We'll then apply the same principle for left, right and up, stopping the player just before a collision.

First, let's give the player a check_collision method to make these checks:

Here, we're moving the player by a specified amount, checking for a collision, and then moving the player back. This back and forth movement happens before the player is drawn to the screen, so the user won't notice anything.

Let's change our onground check to use this method:

Run the game now, and you may be able to notice a very slight difference in how the player stands on the ground from before.

This doesn't yet solve our horizontal and upward collisions problems, though. For that, we'll need to implement our new check_collision method directly into the player's move method. The first thing we'll need to do is prepare the x and y parameters for additional processing:

Then we're going to check for collisions, so we need to start passing boxes into move . We're going to do this for x and y separately, starting with y . We'll check for a collision after moving dy pixels vertically, decrementing dy until we no longer collide with a box:

But wait! This code will only work as intended if we're moving down and dy is positive. If dy is negative, this will just move us further into a collision, not away from it. To fix this, we'll need to import numpy at the top of our file, so we can use numpy.sign .

numpy.sign takes an integer and returns 1 if it's positive, -1 if it's negative, and 0 if it's 0. This is exactly the functionality we need!

Now do the same for dx . As we've already figured out the appropriate dy for our movement, we'll include that in the collision check.

Run the game. The player should now stop when he runs into a wall or jumps into a ceiling.

Where Next?​

If you'd like to continue working on this game, you can find a large number of matching art assets here. Try implementing some of these features:

Пишем платформер на Python, используя pygame

image
Сразу оговорюсь, что здесь написано для самых маленькихначинающих.

Давно хотел попробовать себя в качестве игродела, и недавно выпал случай изучить Python и исполнить давнюю мечту.

Что такое платформер?

Платформер(platformer)— жанр компьютерных игр, в которых основной чертой игрового процесса является прыгание по платформам, лазанье по лестницам, собирание предметов, обычно необходимых для завершения уровня.
Вики

Одними из моих любимых игр данного жанра являются «Super Mario Brothers» и «Super Meat Boy». Давайте попробуем создать нечто среднее между ними.

Самое — самое начало.

Внимание! Используем python ветки 2.х, с 3.х обнаружены проблемы запуска нижеописанных скриптов!

Наверное, не только игры, да и все приложения, использующие pygame начинаются примерно так:

Игра будет «крутиться» в цикле ( while 1), каждую итерацию необходимо перерисовывать всё (фон, платформы, монстров, цифровые сообщения и т.д). Важно заметить, что рисование идет последовательно, т.е. если сперва нарисовать героя, а потом залить фон, то героя видно не будет, учтите это на будущее.

Запустив этот код, мы увидим окно, залитое зелененьким цветом.


(Картинка кликабельна)

Ну что же, начало положено, идём дальше.

Уровень.

А как без него? Под словом «уровень» будем подразумевать ограниченную область виртуального двумерного пространства, заполненную всякой — всячиной, и по которой будет передвигаться наш персонаж.

Для построения уровня создадим двумерный массив m на n. Каждая ячейка (m,n) будет представлять из себя прямоугольник. Прямоугольник может в себе что-то содержать, а может и быть пустым. Мы в прямоугольниках будем рисовать платформы.

Добавим еще константы

Затем добавим объявление уровня в функцию main

И в основной цикл добавим следующее:

Т.е. Мы перебираем двумерный массив level, и, если находим символ «-», то по координатам (x * PLATFORM_WIDTH, y * PLATFORM_HEIGHT), где x,y — индекс в массиве level

Запустив, мы увидим следующее:

Персонаж

Просто кубики на фоне — это очень скучно. Нам нужен наш персонаж, который будет бегать и прыгать по платформам.

Создаём класс нашего героя.

Для удобства, будем держать нашего персонажа в отдельном файле player.py

Что тут интересного?
Начнём с того, что мы создаём новый класс, наследуясь от класса pygame.sprite.Sprite, тем самым наследую все характеристики спрайта.
Cпрайт — это движущееся растровое изображение. Имеет ряд полезных методов и свойств.

self.rect = Rect(x, y, WIDTH, HEIGHT), в этой строчке мы создаем фактические границы нашего персонажа, прямоугольник, по которому мы будем не только перемещать героя, но и проверять его на столкновения. Но об этом чуть ниже.

Метод update(self, left, right)) используется для описания поведения объекта. Переопределяет родительский update(*args) → None. Может вызываться в группах спрайтов.

Метод draw(self, screen) используется для вывода персонажа на экран. Далее мы уберем этот метод и будем использовать более интересный способ отображения героя.

Добавим нашего героя в основную часть программы.

Перед определением уровня добавим определение героя и переменные его перемещения.

В проверку событий добавим следующее:

Т.е. Если нажали на клавишу «лево», то идём влево. Если отпустили — останавливаемся. Так же с кнопкой «право»

Само передвижение вызывается так: (добавляем после перерисовки фона и платформ)

Но, как мы видим, наш серый блок слишком быстро перемещается, добавим ограничение в количестве кадров в секунду. Для этого после определения уровня добавим таймер

И в начало основного цикла добавим следующее:

Завис в воздухе

Да, наш герой в безвыходном положении, он завис в воздухе.
Добавим гравитации и возможности прыгать.

И так, работаем в файле player.py

Добавим еще констант

В метод _init_ добавляем строки:

Добавляем входной аргумент в метод update
def update(self, left, right, up):
И в начало метода добавляем:

И перед строчкой self.rect.x += self.xvel
Добавляем

И добавим в основную часть программы:
После строчки left = right = False
Добавим переменную up

В проверку событий добавим

И изменим вызов метода update, добавив новый аргумент up:
hero.update(left, right)
на

Здесь мы создали силу гравитации, которая будет тянуть нас вниз, постоянно наращивая скорость, если мы не стоим на земле, и прыгать в полете мы не умеем. А мы пока не можем твердо встать на что-то, поэтому на следующей анимации наш герой падает далеко за границы видимости.

Встань обеими ногами на землю свою.

Как узнать, что мы на земле или другой твердой поверхности? Ответ очевиден — использовать проверку на пересечение, но для этого изменим создание платформ.

Создадим еще один файл blocks.py, и перенесем в него описание платформы.

Дальше создадим класс, наследуясь от pygame.sprite.Sprite

Тут нет ни чего нам уже не знакомого, идём дальше.

В основной файле произведем изменения, перед описанием массива level добавим

Группа спрайтов entities будем использовать для отображения всех элементов этой группы.
Массив platforms будем использовать для проверки на пересечение с платформой.

Т.е. создаём экземплр класса Platform, добавляем его в группу спрайтов entities и массив platforms. В entities, чтобы для каждого блока не писать логику отображения. В platforms добавили, чтобы потом проверить массив блоков на пересечение с игроком.

Дальше, весь код генерации уровня выносим из цикла.

И так же строчку
hero.draw(screen) # отображение
Заменим на

Запустив, мы увидим, что ни чего не изменилось. Верно. Ведь мы не проверяем нашего героя на столкновения. Начнём это исправлять.

Работаем в файле player.py

Удаляем метод draw, он нам больше не нужен. И добавляем новый метод collide

В этом методе происходит проверка на пересечение координат героя и платформ, если таковое имеется, то выше описанной логике происходит действие.

Ну, и для того, что бы это всё происходило, необходимо вызывать этот метод.
Изменим число аргументов для метода update, теперь он выглядит так:

И не забудьте изменить его вызов в основном файле.

Т.е. передвинули героя вертикально, проверили на пересечение по вертикали, передвинули горизонтально, снова проверили на пересечение по горизонтали.

Вот, что получится, когда запустим.

Фу[у]! Движущийся прямоугольник — не красиво!

Давайте немного приукрасим нашего МариоБоя.

Начнем с платформ. Для этого в файле blocks.py сделаем небольшие изменения.

Заменим заливку цветом на картинку, для этого строчку
self.image.fill(Color(PLATFORM_COLOR))
Заменим на

Мы загружаем картинку вместо сплошного цвета. Разумеется, файл «platform.png» должен находиться в папке «blocks», которая должна располагаться в каталоге с исходными кодами.

Вот, что получилось

Теперь переходим к нашему герою. Для движущегося объекта нужна не статическая картинка, а анимация. Дабы облегчить себе эту задачу, воспользуемся замечательной библиотекой pyganim . Приступим.

Сперва добавим в блок констант.

Тут, думаю, понятно, анимация разных действий героя.

Теперь добавим следующее в метод __init__

Здесь для каждого действия мы создаем набор анимаций, и включаем их(т.е. Включаем смену кадров).
))
Каждый кадр имеет картинку и время показа.

Осталось в нужный момент показать нужную анимацию.

Добавим смену анимаций в метод update.

Больше, нужно больше места

Ограничение в размере окна мы преодолеем созданием динамической камеры.

Для этого создадим класс Camera

Далее, добавим начальное конфигурирование камеры

Создадим экземпляр камеры, добавим перед основным циклом:

Мы создали внутри большого прямоугольника, размеры которого вычисляются так:

меньший прямоугольник, размером, идентичным размеру окна.

Меньший прямоугольник центрируется относительно главного персонажа(метод update), и все объекты рисуются в меньшем прямоугольнике (метод apply), за счет чего создаётся впечатление движения камеры.

Для работы вышеописанного, нужно изменить рисование объектов.

Заменим строчку
entities.draw(screen) # отображение
На

И перед ней добавим

Теперь можем изменить уровень.

Вот, собственно, и результат

В следующей части, если будет востребовано сообществом, мы создадим свой генератор уровней с блэкджеком и шлюхами с разными типами платформ, монстрами, телепортами, и конечно же, принцессой.

upd pygame можно скачать отсюда, спасибо, Chris_Griffin за замечание
upd1 Вторая часть

Похожие статьи