Пользователь
0,0
рейтинг
16 сентября 2013 в 12:45

Разработка → Пишем платформер на Python, используя pygame из песочницы tutorial

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

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

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


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

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


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


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

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Импортируем библиотеку pygame
import pygame
from pygame import *

#Объявляем переменные
WIN_WIDTH = 800 #Ширина создаваемого окна
WIN_HEIGHT = 640 # Высота
DISPLAY = (WIN_WIDTH, WIN_HEIGHT) # Группируем ширину и высоту в одну переменную
BACKGROUND_COLOR = "#004400"

def main():
    pygame.init() # Инициация PyGame, обязательная строчка 
    screen = pygame.display.set_mode(DISPLAY) # Создаем окошко
    pygame.display.set_caption("Super Mario Boy") # Пишем в шапку
    bg = Surface((WIN_WIDTH,WIN_HEIGHT)) # Создание видимой поверхности
                                         # будем использовать как фон
    bg.fill(Color(BACKGROUND_COLOR))     # Заливаем поверхность сплошным цветом

    while 1: # Основной цикл программы
        for e in pygame.event.get(): # Обрабатываем события
            if e.type == QUIT:
                raise SystemExit, "QUIT"
        screen.blit(bg, (0,0))      # Каждую итерацию необходимо всё перерисовывать 
        pygame.display.update()     # обновление и вывод всех изменений на экран
        

if __name__ == "__main__":
    main()



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

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


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

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

Уровень.



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

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

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

PLATFORM_WIDTH = 32
PLATFORM_HEIGHT = 32
PLATFORM_COLOR = "#FF6262"


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

level = [
       "-------------------------",
       "-                       -",
       "-                       -",
       "-                       -",
       "-            --         -",
       "-                       -",
       "--                      -",
       "-                       -",
       "-                   --- -",
       "-                       -",
       "-                       -",
       "-      ---              -",
       "-                       -",
       "-   -----------        -",
       "-                       -",
       "-                -      -",
       "-                   --  -",
       "-                       -",
       "-                       -",
       "-------------------------"]


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

  x=y=0 # координаты
  for row in level: # вся строка
      for col in row: # каждый символ
          if col == "-":
              #создаем блок, заливаем его цветом и рисеум его
              pf = Surface((PLATFORM_WIDTH,PLATFORM_HEIGHT))
              pf.fill(Color(PLATFORM_COLOR)) 
              screen.blit(pf,(x,y))
                    
          x += PLATFORM_WIDTH #блоки платформы ставятся на ширине блоков
      y += PLATFORM_HEIGHT    #то же самое и с высотой
      x = 0                   #на каждой новой строчке начинаем с нуля


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

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



Персонаж



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

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

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pygame import *

MOVE_SPEED = 7
WIDTH = 22
HEIGHT = 32
COLOR =  "#888888"


class Player(sprite.Sprite):
    def __init__(self, x, y):
        sprite.Sprite.__init__(self)
        self.xvel = 0   #скорость перемещения. 0 - стоять на месте
        self.startX = x # Начальная позиция Х, пригодится когда будем переигрывать уровень
        self.startY = y
        self.image = Surface((WIDTH,HEIGHT))
        self.image.fill(Color(COLOR))
        self.rect = Rect(x, y, WIDTH, HEIGHT) # прямоугольный объект

    def update(self,  left, right):
        if left:
            self.xvel = -MOVE_SPEED # Лево = x- n
 
        if right:
            self.xvel = MOVE_SPEED # Право = x + n
         
        if not(left or right): # стоим, когда нет указаний идти
            self.xvel = 0

        self.rect.x += self.xvel # переносим свои положение на xvel 
   
    def draw(self, screen): # Выводим себя на экран
        screen.blit(self.image, (self.rect.x,self.rect.y))



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

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

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

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

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

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

hero = Player(55,55) # создаем героя по (x,y) координатам
left = right = False    # по умолчанию — стоим


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

if e.type == KEYDOWN and e.key == K_LEFT:
   left = True
if e.type == KEYDOWN and e.key == K_RIGHT:
   right = True

if e.type == KEYUP and e.key == K_RIGHT:
   right = False
if e.type == KEYUP and e.key == K_LEFT:
    left = False


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

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

hero.update(left, right) # передвижение
hero.draw(screen) # отображение


image

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

timer = pygame.time.Clock()


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

timer.tick(60)


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



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

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

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

JUMP_POWER = 10
GRAVITY = 0.35 # Сила, которая будет тянуть нас вниз


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

 self.yvel = 0 # скорость вертикального перемещения
 self.onGround = False # На земле ли я?


Добавляем входной аргумент в метод update
def update(self, left, right, up):
И в начало метода добавляем:
if up:
   if self.onGround: # прыгаем, только когда можем оттолкнуться от земли
       self.yvel = -JUMP_POWER


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

if not self.onGround:
    self.yvel +=  GRAVITY

self.onGround = False; # Мы не знаем, когда мы на земле((   
self.rect.y += self.yvel


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


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

if e.type == KEYDOWN and e.key == K_UP:
       up = True

if e.type == KEYUP and e.key == K_UP:
      up = False


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


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

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



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

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

PLATFORM_WIDTH = 32
PLATFORM_HEIGHT = 32
PLATFORM_COLOR = "#FF6262"


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

class Platform(sprite.Sprite):
    def __init__(self, x, y):
        sprite.Sprite.__init__(self)
        self.image = Surface((PLATFORM_WIDTH, PLATFORM_HEIGHT))
        self.image.fill(Color(PLATFORM_COLOR))
        self.rect = Rect(x, y, PLATFORM_WIDTH, PLATFORM_HEIGHT)


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

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

entities = pygame.sprite.Group() # Все объекты
platforms = [] # то, во что мы будем врезаться или опираться
entities.add(hero)


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

Далее, блок
if col == "-":
   #создаем блок, заливаем его цветом и рисеум его
   pf = Surface((PLATFORM_WIDTH,PLATFORM_HEIGHT))
   pf.fill(Color(PLATFORM_COLOR)) 
   screen.blit(pf,(x,y))


Заменим на
if col == "-":
   pf = Platform(x,y)
   entities.add(pf)
   platforms.append(pf)


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

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

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


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

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

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

def collide(self, xvel, yvel, platforms):
        for p in platforms:
            if sprite.collide_rect(self, p): # если есть пересечение платформы с игроком

                if xvel > 0:                      # если движется вправо
                    self.rect.right = p.rect.left # то не движется вправо

                if xvel < 0:                      # если движется влево
                    self.rect.left = p.rect.right # то не движется влево

                if yvel > 0:                      # если падает вниз
                    self.rect.bottom = p.rect.top # то не падает вниз
                    self.onGround = True          # и становится на что-то твердое
                    self.yvel = 0                 # и энергия падения пропадает

                if yvel < 0:                      # если движется вверх
                    self.rect.top = p.rect.bottom # то не движется вверх
                    self.yvel = 0                 # и энергия прыжка пропадает


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

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

update(self, left, right, up, platforms)


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

И строчки
self.rect.y += self.yvel
self.rect.x += self.xvel # переносим свои положение на xvel


Заменям на:
self.rect.y += self.yvel
self.collide(0, self.yvel, platforms)

self.rect.x += self.xvel # переносим свои положение на xvel
self.collide(self.xvel, 0, platforms)


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

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

image

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



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

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

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


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

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



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

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

ANIMATION_DELAY = 0.1 # скорость смены кадров
ANIMATION_RIGHT = [('mario/r1.png'),
            ('mario/r2.png'),
            ('mario/r3.png'),
            ('mario/r4.png'),
            ('mario/r5.png')]
ANIMATION_LEFT = [('mario/l1.png'),
            ('mario/l2.png'),
            ('mario/l3.png'),
            ('mario/l4.png'),
            ('mario/l5.png')]
ANIMATION_JUMP_LEFT = [('mario/jl.png', 0.1)]
ANIMATION_JUMP_RIGHT = [('mario/jr.png', 0.1)]
ANIMATION_JUMP = [('mario/j.png', 0.1)]
ANIMATION_STAY = [('mario/0.png', 0.1)]


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

Теперь добавим следующее в метод __init__
self.image.set_colorkey(Color(COLOR)) # делаем фон прозрачным
#        Анимация движения вправо
boltAnim = []
for anim in ANIMATION_RIGHT:
   boltAnim.append((anim, ANIMATION_DELAY))
self.boltAnimRight = pyganim.PygAnimation(boltAnim)
self.boltAnimRight.play()
#        Анимация движения влево        
boltAnim = []
for anim in ANIMATION_LEFT:
   boltAnim.append((anim, ANIMATION_DELAY))
self.boltAnimLeft = pyganim.PygAnimation(boltAnim)
self.boltAnimLeft.play()
        
self.boltAnimStay = pyganim.PygAnimation(ANIMATION_STAY)
self.boltAnimStay.play()
self.boltAnimStay.blit(self.image, (0, 0)) # По-умолчанию, стоим
        
self.boltAnimJumpLeft= pyganim.PygAnimation(ANIMATION_JUMP_LEFT)
self.boltAnimJumpLeft.play()
        
self.boltAnimJumpRight= pyganim.PygAnimation(ANIMATION_JUMP_RIGHT)
self.boltAnimJumpRight.play()
        
self.boltAnimJump= pyganim.PygAnimation(ANIMATION_JUMP)
self.boltAnimJump.play()


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

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


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

if up:
    if self.onGround: # прыгаем, только когда можем оттолкнуться от земли
       self.yvel = -JUMP_POWER
     self.image.fill(Color(COLOR))
     self.boltAnimJump.blit(self.image, (0, 0))
                      
if left:
   self.xvel = -MOVE_SPEED # Лево = x- n
   self.image.fill(Color(COLOR))
   if up: # для прыжка влево есть отдельная анимация
      self.boltAnimJumpLeft.blit(self.image, (0, 0))
   else:
      self.boltAnimLeft.blit(self.image, (0, 0))
 
if right:
   self.xvel = MOVE_SPEED # Право = x + n
   self.image.fill(Color(COLOR))
      if up:
         self.boltAnimJumpRight.blit(self.image, (0, 0))
      else:
         self.boltAnimRight.blit(self.image, (0, 0))
         
if not(left or right): # стоим, когда нет указаний идти
   self.xvel = 0
   if not up:
      self.image.fill(Color(COLOR))
      self.boltAnimStay.blit(self.image, (0, 0))
      

Вуаля!
image

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


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

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

class Camera(object):
    def __init__(self, camera_func, width, height):
        self.camera_func = camera_func
        self.state = Rect(0, 0, width, height)
	
    def apply(self, target):
        return target.rect.move(self.state.topleft)

    def update(self, target):
        self.state = self.camera_func(self.state, target.rect)
    


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

def camera_configure(camera, target_rect):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    l, t = -l+WIN_WIDTH / 2, -t+WIN_HEIGHT / 2

    l = min(0, l)                           # Не движемся дальше левой границы
    l = max(-(camera.width-WIN_WIDTH), l)   # Не движемся дальше правой границы
    t = max(-(camera.height-WIN_HEIGHT), t) # Не движемся дальше нижней границы
    t = min(0, t)                           # Не движемся дальше верхней границы

    return Rect(l, t, w, h)      


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

total_level_width  = len(level[0])*PLATFORM_WIDTH # Высчитываем фактическую ширину уровня
total_level_height = len(level)*PLATFORM_HEIGHT   # высоту
   
camera = Camera(camera_configure, total_level_width, total_level_height) 


Что мы сделали?

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

total_level_width  = len(level[0])*PLATFORM_WIDTH # Высчитываем фактическую ширину уровня
total_level_height = len(level)*PLATFORM_HEIGHT   # высоту


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

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

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

Заменим строчку
entities.draw(screen) # отображение
На
for e in entities:
   screen.blit(e.image, camera.apply(e))


И перед ней добавим
camera.update(hero) # центризируем камеру относительно персонажа


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

level = [
       "----------------------------------",
       "-                                -",
       "-                       --       -",
       "-                                -",
       "-            --                  -",
       "-                                -",
       "--                               -",
       "-                                -",
       "-                   ----     --- -",
       "-                                -",
       "--                               -",
       "-                                -",
       "-                            --- -",
       "-                                -",
       "-                                -",
       "-      ---                       -",
       "-                                -",
       "-   -------         ----         -",
       "-                                -",
       "-                         -      -",
       "-                            --  -",
       "-                                -",
       "-                                -",
       "----------------------------------"]


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

Результат можно скачать, ссылка на GitHub

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

upd pygame можно скачать отсюда, спасибо, Chris_Griffin за замечание
upd1 Вторая часть
Владимир @Velese
карма
37,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (46)

  • +7
    Караваны! Это первое, что необходимо реализовать!

    А вообще шикарно, как вспомню в 16 лет делали 2D пародии на Солдата и пр… Делфи, процедуры… Ужс.
    Спасибо, интересно было)
    • +4
      Первая написанная игра, как первый секс — на всю жизнь запоминается)
  • +2
    если будет востребовано сообществом

    Очень востребовано!
    Спасибо за доходчивые описания!
    • +1
      Спасибо! Буду продолжать:)
      • +2
        Всенепременнейше продолжайте, сударь!
  • +1
    Туториал добротный! Правда вместо pyпgame часто выбирают love2d, но принципы примерно одни и те же.
    Есть какие-нибудь законченные игры?
    • 0
      Пока нет. Но это начало
  • +8
    Попробуйте сделать это все без сторонней библиотеки. Это не очень сложно, но удовольствие будет намного больше.
    И выкладывать код на «айфолдер.файлообменник.рф» — это, конечно…
    • +2
      Перезалил на github, спасибо!
    • 0
      Вы наверное имели ввиду без этой специализированной библиотеки, так? Потому, что я не знаю чтоб в питоне можно было без сторонних библиотек ловить нажатия клавиш, или я неправ?
      • 0
        В стандартную поставку python входит Tk/Tkinter, с чьей помощью ловить сторонния нажатия клавиш.
        • 0
          Блин, спасибо, а то на стаковерфло наткнулся как раз на предложения pygame, PyKeylogger, pyHook. Это мне нравится больше.
  • 0
    Запретите менять направление движения, находясь в воздухе. А то очень непривычно смотрится :)

    p.s. Не корректно выразился. Не давать мгновенно гасить импульс, находясь в воздухе. На последнем «ролике» многократно происходит.
    • +1
      Так это фишка аля Super Meat Boy, где нужна реакция ого-го!
      • 0
        Я не играл) Там так же можно: резко гасить импульс и падать отвесно вниз?
        • 0
          Там всё же горизонтальная скорость не тернарна как в данном примере (влево с константной скоростью, вправо с константной скоростью или на месте, в зависимости от нажатия кнопок влево-вправо). Но там очень отзывчивое управление с большим горизонтальным ускорением, возникающим при нажатии влево-вправо. То есть опытный игрок может действительно добиваться схожего эффекта, тормозя в воздухе и сбрасывая импульс до нуля. В общем, как бы невнятно я ни объяснил, поиграйте — это определённо один из лучших и хардкоррных платформеров за последние N лет =)
  • +5
    Спасибо, самое то для не сведующих. Только пару замечаний, если позволите. Готовому коду будет намного уютнее на github, чем в файлообменнике. И еще — не могу запустить ваш пример — как понимаю вы не приложили pygame? Просто если обучалка для совсем новичков (как я, да) — это может быть нетривиальной проблемой.
    • +1
      Спасибо! Дописал в статье на счет библиотеки pygame
  • +3
    Туториал очень хороший, в свое время интересовался pygame, pyglet и прочими фреймворками для разработки игр на Python.
    Не понял, правда, зачем вам такой странный импорт:
    import pygame
    from pygame import *
    

    Подозреваю, что вам больше подойдет
    from pygame.locals import *
    

    Еще хотелось бы отметить, что зачастую основной цикл приложения делают подобным образом:
    running = True
    while running:
        for e in pygame.event.get():
            if e.type == QUIT:
                running = False
    

    Кстати, сейчас зашел на pygame.org и увидел стандартную заглушку. Кто-нибудь знает что случилось с проектом?

    И да, продолжайте, пожалуйста, очень интересна генерация уровней.
    • +1
      «Я не волшебник, я только учусь» (с)
      спасибо за замечания!

      уже около недели захожу туда через сохраненные копии гугла
    • 0
      Что можете сказать про фреимворки, с которыми игрались?
  • +1
    А как в плане производительности? Можно ли на Питоне написать сложную игру с богатой графикой и что бы 60 fps? :) В чью пользу будет сравнение с Unity?
    • +3
      Боюсь, что в пользу Unity. В первую очередь потому что Unity создана для того, чтобы быстро делать игры с хорошей графикой и другими полезными плюшками. А учитывая, что совсем скоро выйдет Unity 4.3, нативно поддерживающий 2D(я имею в виду из-под коробки, а не плагинами), то клепание 2D игрушек станет чуть ли не «мышкопрограммированием».
      • 0
        Единственнаямпроблема юнити — его саппорт. Потому большие компании им не пользуются. Впрочем, это проблема не только юнити, но у них она самая большая.
    • +1
      На нынче очень популярном питоне написан, к примеру, world of tanks. Да и все остальные «большие» игры Варгейминга пишутся и будут писаться на нем, пока будет использоваться движок bigworld. (Понятное дело, речь идет о игровой логике клиента и сервера, что, по сути и есть сама игра)
  • +2
    Introduction to PyGame — Richard Jones (тот, который создал pyweek.org) рассказывает и показывает как разрабатывать на pygame. Заодно как работать с тайлами.

    Ещё интересующимся разработкой игр на питоне стоит сходить на pyweek.org, посмотреть игры, сделанные на интересующих их фреймворках, почитать исходники. Встречается немало интересного.
  • 0
    Я не смог запустить вашу игру:
    pygame.error: Couldn't open mario/r1.png
    

    Кажется, не хватает картинок. Или я что-то не так делаю?
    • 0
      Прошу прощения, исправил
  • 0
    Интересный фреймворк. Пробовал на нем писать игрульки, да только потом забросил :(

  • +1
    Хороший пост.
    Сам недавно писал пару игрулек на pygame.
    Прекрасная библиотека, позволяет буквально за пару часов набросать прототип, достоинства кодинга на питоне играют тут очень большую роль.
    Вот буквально недавно что-то похожее делал: dg-pic.tk/tyqim
  • +1
    Отличный пост. Спасибо. Прям захотелось попробовать самому. Жду продолжения.
    З.Ы. Код на гитхабе с багом (бэктрэйс ниже). Видимо, забыли подключить модуль os в player.py.

    $ python platformerhabrahabr.py
    Traceback (most recent call last):
    File «platformerhabrahabr.py», line 7, in from player import *
    File «SuperMarioBoy/player.py», line 14, in ICON_DIR = os.path.dirname(__file__) # Полный путь к каталогу с файлами
    NameError: name 'os' is not defined
    • 0
      Да, Вы правы. Последний коммит содержал этот баг, исправлено.
      Спасибо!
  • 0
    а где вы брали картинки?
  • +2
    Когда будет вторая часть — не терпиться попробовать погенерить уровней ))
    Заранее спасибо.
  • 0
    У меня Microsoft Windows [Version 6.1.7601]
    Установил по ссылке python-3.3.0.msi и pygame-1.9.2a0.win32-py3.3.msi с дефолтными настройками.

    Первый листинг сохранил в файле list.py
    Запускаю файл list.py:

    c:\Python33>list.py
    File «C:\Python33\list.py», line 25
    raise SystemExit, «QUIT»
    ^
    SyntaxError: invalid syntax

    c:\Python33>

    Что я делаю не так? Это ведь
    написано для самых маленьких начинающих.
    • 0
      Проделал те же операции и оказалось, что действительно не запускается в версии питона 3.3.
      Скачайте версию 2.7 и всё запустится :)
    • +1
      просто исправьте на raise SystemExit(«QUIT») и все заработает.
  • 0
    ---
  • –1
    Удивительно, столько комментариев — и никто не попробовал повторить путь автора. На каждом шагу — засада.
    Вот первый листинг мне удалось запустить(после танцев с версией).
    Второй листинг(где накладываются блоки на фон) — не совсем было понятно куда именно вставлять. Методом проб, ошибок, гугления — нашёл.
    Третий листинг(где создаётся класс игрока) — не работает. Потому что автор ни слова не сказал о том, как его подключать в основной файл. Я это понял только потому, что подсматриваю в рабочий исходник с гитхаба, но во втором листинге он мне не помог, так как сильно отличается от того, что пишет автор.

    Может я не прав и мне надо идти гуглить, курить маны/факи/хелпы…
    Но ведь ориентация «для начинающих».

    Автор, огромное тебе спасибо и респект за труд, но будь добр, повтори путь с нуля по своей статье. В данный момент — это невозможно.
    • 0
      Уважаемый, расскажу как писал статью: вносил изменение в исходный файл, проверял его и потом копировал в статью. Так что ваши претензии не обоснованы
      • 0
        В этом всё и дело. Я решил попробовать python именно на Вашей статье. Если Ваши листинги копировать из статьи в файл проекта — от они не работают. Я, как программист(php) — разобрался. Не знаю, как с новичками, но:
        1. Оказывается, количество табов(точнее позиционирование) перед операторами определяет их отношение к структуре программы. Я впервые с этим столкнулся в этом языке. В статье ни слова об этом.
        2. Исходя из этого, часть УРОВЕНЬ, а точнее листинг
          x=y=0 # координаты
                for row in level: # вся строка
                    for col in row: # каждый символ
        
        ошибочен.
        Должно ведь быть так:
            x=y=0 # координаты
            for row in level: # вся строка
                for col in row: # каждый символ
        
        3. Всё хорошо до тех пор, пока мы не начинаем проверять столкновение героя с препятствиями. У меня дико всё тормозит, даже таймер задержки отключил. Глянул в скачанный исходник — оказывается именно этот цикл надо вынести наружу. В статье я этого не увидел.
      • 0
        Туда-же:
        import os
        
        В статье — ни слова. Это надо подключать в обоих дополнительных файлах(blocks.py и player.py). Я так понял для того, чтобы можно было подключать картинки. Ну и пути прописываются по другому. Вместо
        self.image = image.load("blocks/platform.png")
        
        надо
        self.image = image.load("%s/blocks/platform.png" % ICON_DIR)
        
        и в константы добавить
        ICON_DIR = os.path.dirname(__file__) #  Полный путь к каталогу с файлами
        
        Этого нет в статье.
        • 0
          Но согласитесь, начать писать игру на языке, на котором даже Hello world не написали, немного страновато, ведь в статья называется «Пишем платформер на Python, используя pygame» а не «Изучаем Python».
          На счет первого листинга, да, Вы правы, тут ошибка в табах.
          На счет второго: тот вариант, который описан в статье, имеет право на существование равно тому, что в исходниках на github'e, просто в исходниках вариант кода, который запустится из командной строки.
          Если еще будут вопросы — пишите в личку, чем смогу — помогу )
    • +1
      у меня все получилось…
    • +1
      Данная статья подтолкнула меня к написанию двух симуляторов — солнечной системы и полета управляемой ракеты в ней.
      Так что путь автора повторить можно :-)

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