2013-02-05 3 views
6

С моим кодом ниже, что было бы самым простым и простым способом реализации игровых состояний для управления уровнями? Если бы я хотел начать с экрана заголовка, загрузите уровень и перейдите на следующий уровень после завершения? Если бы кто-то мог объяснить самый простой способ справиться с этим, это было бы здорово!Pygame level/menu states

import pygame 
from pygame import * 

WIN_WIDTH = 1120 - 320 
WIN_HEIGHT = 960 - 320 
HALF_WIDTH = int(WIN_WIDTH/2) 
HALF_HEIGHT = int(WIN_HEIGHT/2) 

DISPLAY = (WIN_WIDTH, WIN_HEIGHT) 
DEPTH = 0 
FLAGS = 0 
CAMERA_SLACK = 30 

def main(): 
    global level 
    pygame.init() 
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH) 
    pygame.display.set_caption("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
    timer = pygame.time.Clock() 
    level = 0 

    bg = Surface((32,32)) 
    bg.convert() 
    bg.fill(Color("#0094FF")) 

    up = left = right = False 
    entities = pygame.sprite.Group() 
    player = Player(32, 32) 
    enemy = Enemy(32,32) 
    platforms = [] 

    x = 0 
    y = 0 

    if level == 0: 
     level = [ 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           ", 
      "           E ", 
      "       PPPPPPPPPPPPPPPP", 
      "       PPPPPPPPPPPPPPPP", 
      "       PPPPPPPPPPPPPPPP", 
      "    PPPPP  PPPPPPPPPPPPPPPP", 
      "       PPPPPPPPPPPPPPPP", 
      "       PPPP   P", 
      "       PPPP   P", 
      "       PPPP  PPPPPPP", 
      "      PPPPPPPPPP  PPPPPPP", 
      "       PPPP  PPPPPPP", 
      "  PPPP     PPPP  PPPPPPP", 
      "       PPPP  PPPPPPP", 
      "       PPPP  PPPPPPP", 
      "       PPPP  PPPPPPP", 
      "PPPPP      PPPP  PPPPPPP", 
      "PPP       PPPP  PPPPPPP", 
      "PPP       PPPP  PPPPPPP", 
      "PPP       PPPP  PPPPPPP", 
      "PPP   PPPPP   PPPP  PPPPPPP", 
      "PPP          PPPP", 
      "PPP          PPPP", 
      "PPP          PPPP", 
      "PPP      PPPPPPPPPPPPPPPPPP", 
      "PPP      PPPPPPPPPPPPPPPPPP", 
      "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
      "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
      "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
      "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
      "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP",] 

     #background = pygame.image.load("Untitled.png") 


    total_level_width = len(level[0]) * 32 
    total_level_height = len(level) * 32 

    # build the level 
    for row in level: 
     for col in row: 
      if col == "P": 
       p = Platform(x, y) 
       platforms.append(p) 
       entities.add(p) 
      if col == "E": 
       e = ExitBlock(x, y) 
       platforms.append(e) 
       entities.add(e) 
      x += 32 
     y += 32 
     x = 0 

    camera = Camera(complex_camera, total_level_width, total_level_height) 
    entities.add(player) 
    entities.add(enemy) 

    while 1: 
     timer.tick(60) 

     for e in pygame.event.get(): 
      if e.type == QUIT: raise SystemExit, "QUIT" 
      if e.type == KEYDOWN and e.key == K_ESCAPE: 
       raise SystemExit, "ESCAPE" 

      if e.type == KEYDOWN and e.key == K_UP: 
       up = True 
      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_UP: 
       up = False 
      if e.type == KEYUP and e.key == K_LEFT: 
       left = False 
      if e.type == KEYUP and e.key == K_RIGHT: 
       right = False 

     # draw background 
     for y in range(20): 
      for x in range(25): 
       screen.blit(bg, (x * 32, y * 32)) 

     # draw background 
     #screen.blit(background, camera.apply((0,0))) 
     #draw entities 
     for e in entities: 
      screen.blit(e.image, camera.apply(e)) 
     # update player, update camera, and refresh 
     player.update(up, left, right, platforms) 
     enemy.update(platforms) 
     camera.update(player) 
     pygame.display.flip() 

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): 
     try: 
      return target.rect.move(self.state.topleft) 
     except AttributeError: 
      return map(sum, zip(target, self.state.topleft)) 

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

def complex_camera(camera, target_rect): 
    l, t, _, _ = target_rect 
    _, _, w, h = camera 
    l, t, _, _ = -l + HALF_WIDTH, -t +HALF_HEIGHT, w, h 

    l = min(0, l)       # stop scrolling left 
    l = max(-(camera.width - WIN_WIDTH), l) # stop scrolling right 
    t = max(-(camera.height-WIN_HEIGHT), t) # stop scrolling bottom 

    return Rect(l, t, w, h) 

class Entity(pygame.sprite.Sprite): 
    def __init__(self): 
     pygame.sprite.Sprite.__init__(self) 

class Player(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     self.xvel = 0 
     self.yvel = 0 
     self.onGround = False 
     self.image = Surface((32,32)) 
     self.image.fill(Color("#0000FF")) 
     self.image.convert() 
     self.rect = Rect(200, 1200, 32, 32) 


    def update(self, up, left, right, platforms): 
     if self.rect.top > 1440 or self.rect.top < 0: 
      main() 
     if self.rect.left > 1408 or self.rect.right < 0: 
      main() 
     if up: 
      if self.onGround: 
       self.yvel = 0 
       self.yvel -= 10 # only jump if on the ground 
     if left: 
      self.xvel = -10 
     if right: 
      self.xvel = 10 
     if not self.onGround: 
      self.yvel += 0.3 # only accelerate with gravity if in the air 
      if self.yvel > 80: self.yvel = 80 # max falling speed 
     if not(left or right): 
      self.xvel = 0 

     self.rect.left += self.xvel # increment in x direction 
     self.collide(self.xvel, 0, platforms) # do x-axis collisions 
     self.rect.top += self.yvel # increment in y direction 
     self.onGround = False; # assuming we're in the air 
     self.collide(0, self.yvel, platforms) # do y-axis collisions 

    def collide(self, xvel, yvel, platforms): 
     for p in platforms: 
      if pygame.sprite.collide_rect(self, p): 
       if isinstance(p, ExitBlock): 
        pygame.event.post(pygame.event.Event(QUIT)) 
       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 
       if yvel < 0: 
        self.rect.top = p.rect.bottom 


class Enemy(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     self.yVel = 0 
     self.xVel = 0 
     self.image = Surface((32,32)) 
     self.image.fill(Color("#00FF00")) 
     self.image.convert() 
     self.rect = Rect(300, 1200, 32, 32) 
     self.onGround = False 
     self.right_dis = False 

    def update(self, platforms): 
     if not self.onGround: 
      self.yVel += 0.3 

     if self.rect.left == 96: 
      self.right_dis = False 
     if self.rect.right == 480: 
      self.right_dis = True 
     if not self.right_dis: 
      self.xVel = 2 
     if self.right_dis: 
      self.xVel = -2 

     self.rect.left += self.xVel # increment in x direction 
     self.collide(self.xVel, 0, platforms) # do x-axis collisions 
     self.rect.top += self.yVel # increment in y direction 
     self.onGround = False; # assuming we're in the air 
     self.collide(0, self.yVel, platforms) # do y-axis collisions 

    def collide(self, xVel, yVel, platforms): 
     for p in platforms: 
      if pygame.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 
       if yVel < 0: 
        self.rect.top = p.rect.bottom 

class Platform(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     #self.image = Surface([32, 32], pygame.SRCALPHA, 32) #makes blocks invisible for much better artwork 
     self.image = Surface((32,32)) #makes blocks visible for building levels 
     self.image.convert() 
     self.rect = Rect(x, y, 32, 32) 

    def update(self): 
     pass 

class ExitBlock(Platform): 
    def __init__(self, x, y): 
     Platform.__init__(self, x, y) 
     self.image = pygame.image.load("end.png") 




if __name__ == "__main__": 
    main() 
+0

Как только у вас есть функция для загрузки уровня, на экране заголовка нажмите кнопку «load_map (« level1 »)'. level1 будет иметь проверку выигрыша уровня, поэтому по завершении этой карты загрузить следующую карту. 'load_map (" level2 ")' и т. д. – ninMonkey

ответ

25

Прежде всего, давайте избавимся от этих уродливых if-блоков:

for e in pygame.event.get(): 
    if e.type == QUIT: raise SystemExit, "QUIT" 
    if e.type == KEYDOWN and e.key == K_ESCAPE: 
     raise SystemExit, "ESCAPE" 

    if e.type == KEYDOWN and e.key == K_UP: 
     up = True 
    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_UP: 
     up = False 
    if e.type == KEYUP and e.key == K_LEFT: 
     left = False 
    if e.type == KEYUP and e.key == K_RIGHT: 
     right = False 

Мы можем переписать как:

for e in pygame.event.get(): 
    if e.type == QUIT: raise SystemExit, "QUIT" 
    if e.type == KEYDOWN and e.key == K_ESCAPE: 
     raise SystemExit, "ESCAPE" 

pressed = pygame.key.get_pressed() 
up, left, right = [pressed[key] for key in (K_UP, K_LEFT, K_RIGHT)] 

Это пригодится в дальнейшем.


Перейти к теме: Что мы хотим, чтобы это куча различных сцен. Каждый Сцена должна нести ответственность за собственный рендеринг экрана и обработку событий.

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

class Scene(object): 
    def __init__(self): 
     pass 

    def render(self, screen): 
     raise NotImplementedError 

    def update(self): 
     raise NotImplementedError 

    def handle_events(self, events): 
     raise NotImplementedError 

Наш план является перезапись каждый метод в каждом подклассе, поэтому мы поднимаем NotImplementedError S в базовом классе так легко узнайте, если мы забудем это сделать (мы также могли бы использовать ABC, но давайте будем простыми).

Теперь давайте поместим все, что связано с состоянием бегущей игры (в основном это все) в новый класс GameScene.

class GameScene(Scene): 
    def __init__(self): 
     super(GameScene, self).__init__() 
     level = 0 
     self.bg = Surface((32,32)) 
     self.bg.convert() 
     self.bg.fill(Color("#0094FF")) 
     up = left = right = False 
     self.entities = pygame.sprite.Group() 
     self.player = Player(32, 32) 
     self.enemy = Enemy(32,32) 
     self.platforms = [] 

     x = 0 
     y = 0 

     if level == 0: 
      level = [ 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           ", 
       "           E ", 
       "       PPPPPPPPPPPPPPPP", 
       "       PPPPPPPPPPPPPPPP", 
       "       PPPPPPPPPPPPPPPP", 
       "    PPPPP  PPPPPPPPPPPPPPPP", 
       "       PPPPPPPPPPPPPPPP", 
       "       PPPP   P", 
       "       PPPP   P", 
       "       PPPP  PPPPPPP", 
       "      PPPPPPPPPP  PPPPPPP", 
       "       PPPP  PPPPPPP", 
       "  PPPP     PPPP  PPPPPPP", 
       "       PPPP  PPPPPPP", 
       "       PPPP  PPPPPPP", 
       "       PPPP  PPPPPPP", 
       "PPPPP      PPPP  PPPPPPP", 
       "PPP       PPPP  PPPPPPP", 
       "PPP       PPPP  PPPPPPP", 
       "PPP       PPPP  PPPPPPP", 
       "PPP   PPPPP   PPPP  PPPPPPP", 
       "PPP          PPPP", 
       "PPP          PPPP", 
       "PPP          PPPP", 
       "PPP      PPPPPPPPPPPPPPPPPP", 
       "PPP      PPPPPPPPPPPPPPPPPP", 
       "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
       "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
       "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
       "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
       "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP",] 

      #background = pygame.image.load("Untitled.png") 


     total_level_width = len(level[0]) * 32 
     total_level_height = len(level) * 32 

     # build the level 
     for row in level: 
      for col in row: 
       if col == "P": 
        p = Platform(x, y) 
        self.platforms.append(p) 
        self.entities.add(p) 
       if col == "E": 
        e = ExitBlock(x, y) 
        self.platforms.append(e) 
        self.entities.add(e) 
       x += 32 
      y += 32 
      x = 0 

     self.camera = Camera(complex_camera, total_level_width, total_level_height) 
     self.entities.add(self.player) 
     self.entities.add(self.enemy) 

    def render(self, screen): 
     for y in range(20): 
      for x in range(25): 
       screen.blit(self.bg, (x * 32, y * 32)) 

     for e in self.entities: 
      screen.blit(e.image, self.camera.apply(e)) 

    def update(self): 
     pressed = pygame.key.get_pressed() 
     up, left, right = [pressed[key] for key in (K_UP, K_LEFT, K_RIGHT)] 
     self.player.update(up, left, right, self.platforms) 
     self.enemy.update(self.platforms) 
     self.camera.update(self.player) 

    def handle_events(self, events): 
     for e in events: 
      if e.type == KEYDOWN and e.key == K_ESCAPE: 
       pass #somehow go back to menu 

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

Теперь нам нужно изменить main -функции на самом деле использовать этот класс:

def main(): 
    pygame.init() 
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH) 
    pygame.display.set_caption("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
    timer = pygame.time.Clock() 
    running = True 

    scene = GameScene() 

    while running: 
     timer.tick(60) 

     if pygame.event.get(QUIT): 
      running = False 
      return 
     scene.handle_events(pygame.event.get()) 
     scene.update() 
     scene.render(screen) 
     pygame.display.flip() 

Обратите внимание, что я поменял две маленьких вещей: я использую pygame.event.get(QUIT) только получить возможную QUIT -Event первым, так как это единственное событие, которое мы вступаем в наш основной цикл. Все остальные события передаются непосредственно на текущую сцену: scene.handle_events(pygame.event.get()).

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

Давайте создадим меню заголовка:

class TitleScene(object): 

    def __init__(self): 
     super(TitleScene, self).__init__() 
     self.font = pygame.font.SysFont('Arial', 56) 
     self.sfont = pygame.font.SysFont('Arial', 32) 

    def render(self, screen): 
     # beware: ugly! 
     screen.fill((0, 200, 0)) 
     text1 = self.font.render('Crazy Game', True, (255, 255, 255)) 
     text2 = self.sfont.render('> press space to start <', True, (255, 255, 255)) 
     screen.blit(text1, (200, 50)) 
     screen.blit(text2, (200, 350)) 

    def update(self): 
     pass 

    def handle_events(self, events): 
     for e in events: 
      if e.type == KEYDOWN and e.key == K_SPACE: 
       self.manager.go_to(GameScene(0)) 

Это просто показывает зеленый фон и текст. Если игрок нажимает SPACE, мы хотим начать первый уровень. Обратите внимание, эту строку:

self.manager.go_to(GameScene(0)) 

Здесь я прохожу аргумент 0 к GameScene класса, так что давайте изменить его так, что принимает этот параметр:

class GameScene(Scene): 
    def __init__(self, level): 
     ... 

линия level = 0 может быть удалена, как вы уже догадались, ,

Итак, что это такое self.manager? Это всего лишь небольшой класс помощников, который управляет сценами для нас.

class SceneMananger(object): 
    def __init__(self): 
     self.go_to(TitleScene()) 

    def go_to(self, scene): 
     self.scene = scene 
     self.scene.manager = self 

Она начинается с заглавной сценой и устанавливает каждый из сцен manager поля к себе, чтобы позволить изменение текущей сцены. Есть много возможностей, как реализовать такой менеджер сцены, и это самый простой подход. Недостатком является то, что каждая сцена должна знать, какая сцена происходит после нее, но это не должно нас беспокоить прямо сейчас.

Давайте использовать наш новый SceneMananger:

def main(): 
    pygame.init() 
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH) 
    pygame.display.set_caption("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
    timer = pygame.time.Clock() 
    running = True 

    manager = SceneMananger() 

    while running: 
     timer.tick(60) 

     if pygame.event.get(QUIT): 
      running = False 
      return 
     manager.scene.handle_events(pygame.event.get()) 
     manager.scene.update() 
     manager.scene.render(screen) 
     pygame.display.flip() 

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

class CustomScene(object): 

    def __init__(self, text): 
     self.text = text 
     super(CustomScene, self).__init__() 
     self.font = pygame.font.SysFont('Arial', 56) 

    def render(self, screen): 
     # ugly! 
     screen.fill((0, 200, 0)) 
     text1 = self.font.render(self.text, True, (255, 255, 255)) 
     screen.blit(text1, (200, 50)) 

    def update(self): 
     pass 

    def handle_events(self, events): 
     for e in events: 
      if e.type == KEYDOWN: 
       self.manager.go_to(TitleScene()) 

Ниже приведен полный код. Обратите внимание на изменения класса Player: вместо вызова функции main он вызывает методы на сцене, чтобы указать, что игрок достиг выхода или умер.

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

Я извлек описание уровней в словарь по имени levels, поэтому будет легко изменить и добавить уровни по мере необходимости (позже вы, вероятно, захотите один файл на уровень, так что это хороший старт). Он может быть расширен, чтобы удерживать начальную позицию игрока, но вы также можете создать специальную плитку, например * для начальной позиции и E для врага в описании уровня.

import pygame 
from pygame import * 

WIN_WIDTH = 1120 - 320 
WIN_HEIGHT = 960 - 320 
HALF_WIDTH = int(WIN_WIDTH/2) 
HALF_HEIGHT = int(WIN_HEIGHT/2) 

DISPLAY = (WIN_WIDTH, WIN_HEIGHT) 
DEPTH = 0 
FLAGS = 0 
CAMERA_SLACK = 30 

levels = {0: {'level': [ 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           E ", 
        "       PPPPPPPPPPPPPPPP", 
        "       PPPPPPPPPPPPPPPP", 
        "       PPPPPPPPPPPPPPPP", 
        "    PPPPP  PPPPPPPPPPPPPPPP", 
        "       PPPPPPPPPPPPPPPP", 
        "       PPPP   P", 
        "       PPPP   P", 
        "       PPPP  PPPPPPP", 
        "      PPPPPPPPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "  PPPP     PPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "PPPPP      PPPP  PPPPPPP", 
        "PPP       PPPP  PPPPPPP", 
        "PPP       PPPP  PPPPPPP", 
        "PPP       PPPP  PPPPPPP", 
        "PPP   PPPPP   PPPP  PPPPPPP", 
        "PPP          PPPP", 
        "PPP          PPPP", 
        "PPP          PPPP", 
        "PPP      PPPPPPPPPPPPPPPPPP", 
        "PPP      PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP",], 
      'enemies': [(9, 38)]}, 
      1: {'level': [ 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           ", 
        "           E ", 
        "       PPPPPPPPPPPPPPPP", 
        "       PPPPPPPPPPPPPPPP", 
        "       PPPPPPPPPPPPPPPP", 
        "    PPPPP  PPPPPPPPPPPPPPPP", 
        "       PPPPPPPPPPPPPPPP", 
        "       PPPP   P", 
        "       PPPP   P", 
        "       PPPP  PPPPPPP", 
        "      PPPPPPPPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "  PPPP     PPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "       PPPP  PPPPPPP", 
        "PPPPP      PPPP  PPPPPPP", 
        "PPP     PPPPPPPPPPP  PPPPPPP", 
        "PPP       PPPP  PPPPPPP", 
        "PPP       PPPP  PPPPPPP", 
        "PPP    PPPPPPPP PPPP  PPPPPPP", 
        "PPP          PPPP", 
        "PPP          PPPP", 
        "PPP   PPPPP      PPPP", 
        "PPP   P   PPPPPPPPPPPPPPPPPP", 
        "PPP   P PPPPPPPPPPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP", 
        "PPPPPPPPPPPPPPP   PPPPPPPPPPPPPPPPPP",], 
      'enemies': [(9, 38), (18, 38), (15, 15)]}} 

class Scene(object): 
    def __init__(self): 
     pass 

    def render(self, screen): 
     raise NotImplementedError 

    def update(self): 
     raise NotImplementedError 

    def handle_events(self, events): 
     raise NotImplementedError 

class GameScene(Scene): 
    def __init__(self, levelno): 
     super(GameScene, self).__init__() 
     self.bg = Surface((32,32)) 
     self.bg.convert() 
     self.bg.fill(Color("#0094FF")) 
     up = left = right = False 
     self.entities = pygame.sprite.Group() 
     self.player = Player(5, 40) 
     self.player.scene = self 
     self.platforms = [] 

     self.levelno = levelno 

     levelinfo = levels[levelno] 
     self.enemies = [Enemy(*pos) for pos in levelinfo['enemies']] 

     level = levelinfo['level'] 
     total_level_width = len(level[0]) * 32 
     total_level_height = len(level) * 32 

     # build the level 
     x = 0 
     y = 0 
     for row in level: 
      for col in row: 
       if col == "P": 
        p = Platform(x, y) 
        self.platforms.append(p) 
        self.entities.add(p) 
       if col == "E": 
        e = ExitBlock(x, y) 
        self.platforms.append(e) 
        self.entities.add(e) 
       x += 32 
      y += 32 
      x = 0 

     self.camera = Camera(complex_camera, total_level_width, total_level_height) 
     self.entities.add(self.player) 
     for e in self.enemies: 
      self.entities.add(e) 

    def render(self, screen): 
     for y in range(20): 
      for x in range(25): 
       screen.blit(self.bg, (x * 32, y * 32)) 

     for e in self.entities: 
      screen.blit(e.image, self.camera.apply(e)) 

    def update(self): 
     pressed = pygame.key.get_pressed() 
     up, left, right = [pressed[key] for key in (K_UP, K_LEFT, K_RIGHT)] 
     self.player.update(up, left, right, self.platforms) 

     for e in self.enemies: 
      e.update(self.platforms) 

     self.camera.update(self.player) 

    def exit(self): 
     if self.levelno+1 in levels: 
      self.manager.go_to(GameScene(self.levelno+1)) 
     else: 
      self.manager.go_to(CustomScene("You win!")) 

    def die(self): 
     self.manager.go_to(CustomScene("You lose!")) 

    def handle_events(self, events): 
     for e in events: 
      if e.type == KEYDOWN and e.key == K_ESCAPE: 
       self.manager.go_to(TitleScene()) 

class CustomScene(object): 

    def __init__(self, text): 
     self.text = text 
     super(CustomScene, self).__init__() 
     self.font = pygame.font.SysFont('Arial', 56) 

    def render(self, screen): 
     # ugly! 
     screen.fill((0, 200, 0)) 
     text1 = self.font.render(self.text, True, (255, 255, 255)) 
     screen.blit(text1, (200, 50)) 

    def update(self): 
     pass 

    def handle_events(self, events): 
     for e in events: 
      if e.type == KEYDOWN: 
       self.manager.go_to(TitleScene()) 

class TitleScene(object): 

    def __init__(self): 
     super(TitleScene, self).__init__() 
     self.font = pygame.font.SysFont('Arial', 56) 
     self.sfont = pygame.font.SysFont('Arial', 32) 

    def render(self, screen): 
     # ugly! 
     screen.fill((0, 200, 0)) 
     text1 = self.font.render('Crazy Game', True, (255, 255, 255)) 
     text2 = self.sfont.render('> press space to start <', True, (255, 255, 255)) 
     screen.blit(text1, (200, 50)) 
     screen.blit(text2, (200, 350)) 

    def update(self): 
     pass 

    def handle_events(self, events): 
     for e in events: 
      if e.type == KEYDOWN and e.key == K_SPACE: 
       self.manager.go_to(GameScene(0)) 

class SceneMananger(object): 
    def __init__(self): 
     self.go_to(TitleScene()) 

    def go_to(self, scene): 
     self.scene = scene 
     self.scene.manager = self 

def main(): 
    pygame.init() 
    screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH) 
    pygame.display.set_caption("ABCDEFGHIJKLMNOPQRSTUVWXYZ") 
    timer = pygame.time.Clock() 
    running = True 

    manager = SceneMananger() 

    while running: 
     timer.tick(60) 

     if pygame.event.get(QUIT): 
      running = False 
      return 
     manager.scene.handle_events(pygame.event.get()) 
     manager.scene.update() 
     manager.scene.render(screen) 
     pygame.display.flip() 

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): 
     try: 
      return target.rect.move(self.state.topleft) 
     except AttributeError: 
      return map(sum, zip(target, self.state.topleft)) 

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

def complex_camera(camera, target_rect): 
    l, t, _, _ = target_rect 
    _, _, w, h = camera 
    l, t, _, _ = -l + HALF_WIDTH, -t +HALF_HEIGHT, w, h 

    l = min(0, l)       # stop scrolling left 
    l = max(-(camera.width - WIN_WIDTH), l) # stop scrolling right 
    t = max(-(camera.height-WIN_HEIGHT), t) # stop scrolling bottom 

    return Rect(l, t, w, h) 

class Entity(pygame.sprite.Sprite): 
    def __init__(self): 
     pygame.sprite.Sprite.__init__(self) 

class Player(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     self.xvel = 0 
     self.yvel = 0 
     self.onGround = False 
     self.image = Surface((32,32)) 
     self.image.fill(Color("#0000FF")) 
     self.image.convert() 
     self.rect = Rect(x*32, y*32, 32, 32) 

    def update(self, up, left, right, platforms): 
     if self.rect.top > 1440 or self.rect.top < 0: 
      self.scene.die() 
     if self.rect.left > 1408 or self.rect.right < 0: 
      self.scene.die() 
     if up: 
      if self.onGround: 
       self.yvel = 0 
       self.yvel -= 10 # only jump if on the ground 
     if left: 
      self.xvel = -10 
     if right: 
      self.xvel = 10 
     if not self.onGround: 
      self.yvel += 0.3 # only accelerate with gravity if in the air 
      if self.yvel > 80: self.yvel = 80 # max falling speed 
     if not(left or right): 
      self.xvel = 0 

     self.rect.left += self.xvel # increment in x direction 
     if self.collide(self.xvel, 0, platforms): # do x-axis collisions 
      self.rect.top += self.yvel # increment in y direction 
      self.onGround = False; # assuming we're in the air 
      self.collide(0, self.yvel, platforms) # do y-axis collisions 

    def collide(self, xvel, yvel, platforms): 
     for p in platforms: 
      if pygame.sprite.collide_rect(self, p): 
       if isinstance(p, ExitBlock): 
        self.scene.exit() 
        return False 
       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 
       if yvel < 0: 
        self.rect.top = p.rect.bottom 
     return True 

class Enemy(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     self.yVel = 0 
     self.xVel = 2 # start moving immediately 
     self.image = Surface((32,32)) 
     self.image.fill(Color("#00FF00")) 
     self.image.convert() 
     self.rect = Rect(x*32, y*32, 32, 32) 
     self.onGround = False 

    def update(self, platforms): 
     if not self.onGround: 
      self.yVel += 0.3 

     # no need for right_dis to be a member of the class, 
     # since we know we are moving right if self.xVel > 0 
     right_dis = self.xVel > 0 

     # create a point at our left (or right) feet 
     # to check if we reached the end of the platform 
     m = (1, 1) if right_dis else (-1, 1) 
     p = self.rect.bottomright if right_dis else self.rect.bottomleft 
     fp = map(sum, zip(m, p)) 

     # if there's no platform in front of us, change the direction 
     collide = any(p for p in platforms if p.rect.collidepoint(fp)) 
     if not collide: 
      self.xVel *= -1 

     self.rect.left += self.xVel # increment in x direction 
     self.collide(self.xVel, 0, platforms) # do x-axis collisions 
     self.rect.top += self.yVel # increment in y direction 
     self.onGround = False; # assuming we're in the air 
     self.collide(0, self.yVel, platforms) # do y-axis collisions 

    def collide(self, xVel, yVel, platforms): 
     for p in platforms: 
      if pygame.sprite.collide_rect(self, p): 
       if xVel > 0: 
        self.rect.right = p.rect.left 
        self.xVel *= -1 # hit wall, so change direction 
       if xVel < 0: 
        self.rect.left = p.rect.right 
        self.xVel *= -1 # hit wall, so change direction 
       if yVel > 0: 
        self.rect.bottom = p.rect.top 
        self.onGround = True 
       if yVel < 0: 
        self.rect.top = p.rect.bottom 

class Platform(Entity): 
    def __init__(self, x, y): 
     Entity.__init__(self) 
     #self.image = Surface([32, 32], pygame.SRCALPHA, 32) #makes blocks invisible for much better artwork 
     self.image = Surface((32,32)) #makes blocks visible for building levels 
     self.image.convert() 
     self.rect = Rect(x, y, 32, 32) 

    def update(self): 
     pass 

class ExitBlock(Platform): 
    def __init__(self, x, y): 
     Platform.__init__(self, x, y) 
     self.image = Surface((32,32)) #makes blocks visible for building levels 
     self.image.convert() 
     self.rect = Rect(x, y, 32, 32) 




if __name__ == "__main__": 
    main() 
+0

Это потрясающе полезно поблагодарить вас за то, что вы так подробно объясняете!Это было действительно очень полезно и многому меня научило. У меня есть один вопрос о обнаружении столкновений, который вы использовали для столкновения со стенами, я мог бы легко проверить наличие столкновений с игроком, проверив наличие столкновения с сущностями [], и если столкновение - это игрок, тогда сделайте что-нибудь, я прав? – user1758231

+0

@ user1758231 Простым способом было бы взять 'rect' игрока и использовать [' Rect.collidelist'] (http://www.pygame.org/docs/ref/rect.html#Rect.collidelist) чтобы проверить, сталкивается ли он с прямым врагом, что-то вроде 'if self.player.rect.collidelist (e.rect для e in self.enemies) ...' – sloth

0

Я также создал игру, в которой у меня есть игровое меню, меню уровней, загрузочная часть и игровая часть.
То, как я это делал, было в основной игровой петле,
Я прошел через кучу высказываний elif, чтобы определить, в каком «режиме» находится игра, и делает соответствующие действия.
Кажется, что это работает очень хорошо, и я предлагаю вам попробовать то же самое.

Я понимаю, что мой код действительно длинный, но если вы пойдете туда, где сказано #game loop (используйте ctrl + f, чтобы найти его), вы можете увидеть elifs для определения режима. Надеюсь это поможет.

#basic stuff 
import pygame, sys, random 
pygame.init() 
window=pygame.display.set_mode((1500, 800), pygame.FULLSCREEN) 
winrect=window.get_rect() 

#colors 
GREEN=(19, 225, 30) 
BLUE=(41, 2, 245) 
YELLOW=(251, 240, 32) 
WHITE=(255, 255, 255) 
BLACK=(0, 0, 0) 
RED=(255, 0, 0) 

#text 
bigfont=pygame.font.SysFont('calibri', 75) 
font=pygame.font.SysFont('calibri', 40) 
texts={} 

so=bigfont.render('Ball Bounce', True, BLUE) 
rect=so.get_rect() 
rect.top=winrect.top+100 
rect.centerx=winrect.centerx 
texts['title']=[so, rect] 

so=font.render('Start', True, BLUE) 
rect=so.get_rect() 
so1=pygame.Surface((400, 50)) 
so2=pygame.Surface((400, 50)) 
rect1=so1.get_rect() 
so1.fill(YELLOW) 
so2.fill(RED) 
pygame.draw.rect(so1, BLACK, rect1, 5) 
pygame.draw.rect(so2, BLACK, rect1, 5) 
rect.center=rect1.center 
so1.blit(so, rect) 
so2.blit(so, rect) 
rect1.centerx=winrect.centerx 
rect1.top=texts['title'][1].top+300 
texts['start']=[so1, rect1, so2] 

so=bigfont.render('Levels', True, BLUE) 
rect=so.get_rect() 
rect.centerx=winrect.centerx 
rect.top=winrect.top+100 
texts['levels']=[so, rect] 

#levels [locked, unlocked, completed/mouseover, rect, state(locked, unlocked, completed)] 
levels=[] 
lock=pygame.image.load('images/lock.png').convert() 
lock=pygame.transform.scale(lock, (100, 100)) 
lock.set_colorkey(lock.get_at((1, 1))) 
for i in range(1, 21): 
    so=pygame.Surface((100, 100)) 
    so.fill(YELLOW) 
    rect=so.get_rect() 
    pygame.draw.rect(so, BLACK, rect, 5) 
    so1=pygame.Surface((100, 100)) 
    so1.fill(RED) 
    pygame.draw.rect(so1, BLACK, rect, 5) 
    text=font.render(str(i), True, BLUE) 
    textrect=text.get_rect() 
    textrect.center=rect.center 
    so.blit(text, textrect) 
    so1.blit(text, textrect) 
    locked=pygame.Surface((100, 100)) 
    locked.blit(so, rect) 
    locked.blit(lock, lock.get_rect()) 
    if i<=5: 
     rect.top=texts['levels'][1].bottom+25 
    elif i<=10: 
     rect.top=levels[0][3].bottom+50 
    elif i<=15: 
     rect.top=levels[7][3].bottom+50 
    else: 
     rect.top=levels[12][3].bottom+50 
    if i==1 or i==6 or i==11 or i==16: 
     rect.right=winrect.centerx-200 
    elif i==2 or i==7 or i==12 or i==17: 
     rect.right=winrect.centerx-75 
    elif i==3 or i==8 or i==13 or i==18: 
     rect.centerx=winrect.centerx 
    elif i==4 or i==9 or i==14 or i==19: 
     rect.left=winrect.centerx+75 
    else: 
     rect.left=winrect.centerx+200 
    if i==1: 
     levels.append([locked, so, so1, rect, 1]) 
    else: 
     levels.append([locked, so, so1, rect, 1]) 

#Wall class (0=horizontal, 1=vertical) 
class cwall(pygame.Rect): 
    'orientation (hor, vert), location, holesize, winrect' 
    def __init__(self, orientation, location, holesize, winrect): 
     self.orientation=orientation 
     if orientation==0: 
      self.height=5 
      self.width=winrect.width 
      self.centery=location 
     if orientation==1: 
      self.width=5 
      self.height=winrect.height 
      self.centerx=location 
     self.holesize=holesize 
     self.bbottomright=round(pygame.mouse.get_pos()[self.orientation]+self.holesize/2) 
     self.ttopleft=round(pygame.mouse.get_pos()[self.orientation]-self.holesize/2) 
    def update(self): 
     self.bbottomright=round(pygame.mouse.get_pos()[self.orientation]+self.holesize/2) 
     self.ttopleft=round(pygame.mouse.get_pos()[self.orientation]-self.holesize/2) 
     if self.bbottomright<self.holesize: 
      self.bbottomright=self.holesize 
     if self.ttopleft>self.right-self.holesize and self.orientation==0: 
      self.ttopleft=self.right-self.holesize 
     if self.ttopleft>self.bottom-self.holesize and self.orientation==1: 
      self.ttopleft=self.bottom-self.holesize 

#Ball Class 
class cball(pygame.Rect): 
    'diameter, speed, color, winrect' 
    def __init__(self, diameter, speed, color, winrect): 
     self.width=diameter 
     self.height=diameter 
     self.speed=speed 
     self.color=color 
     self.direction=random.randint(1, 4) 
     self.center=(random.randint(round(diameter/2), round(winrect.right-diameter/2)), random.randint(round(diameter/2), round(winrect.bottom-diameter/2))) 
    def update(self, winrect, walls): 
     if self.direction/2==round(self.direction/2): 
      self.right+=self.speed 
     else: 
      self.right-=self.speed 
     if self.direction<=2: 
      self.top+=self.speed 
     else: 
      self.top-=self.speed 
     for wall in walls: 
      if wall.collidepoint(self.center): 
       if wall.orientation==0 and (self.centerx<wall.ttopleft or self.centerx>wall.bbottomright): 
        if self.direction==1: 
         self.direction=3 
         self.bottom=wall.top 
        elif self.direction==2: 
         self.direction=4 
         self.bottom=wall.top 
        elif self.direction==3: 
         self.direction=1 
         self.top=wall.bottom 
        else: 
         self.direction=2 
         self.top=wall.bottom 
       elif wall.orientation==1 and (self.centery<wall.ttopleft or self.centery>wall.bbottomright): 
        if self.direction==1: 
         self.direction=2 
         self.left=wall.right 
        elif self.direction==2: 
         self.direction=1 
         self.right=wall.left 
        elif self.direction==3: 
         self.direction=4 
         self.left=wall.right 
        else: 
         self.direction=3 
         self.right=wall.left 
      elif wall.orientation==0: 
       if self.bottom>wall.top and self.centery<wall.top and (self.centerx<wall.ttopleft or self.centerx>wall.bbottomright): 
        if self.direction==1: 
         self.direction=3 
         self.bottom=wall.top 
        elif self.direction==2: 
         self.direction=4 
         self.bottom=wall.top 
       elif self.top<wall.bottom and self.centery>wall.bottom and (self.centerx<wall.ttopleft or self.centerx>wall.bbottomright): 
        if self.direction==3: 
         self.direction=1 
         self.top=wall.bottom 
        if self.direction==4: 
         self.direction=2 
         self.top=wall.bottom 
      else: 
       if self.left<wall.right and self.centerx>wall.right and (self.centery<wall.ttopleft or self.centery>wall.bbottomright): 
        if self.direction==1: 
         self.direction=2 
         self.left=wall.right 
        elif self.direction==3: 
         self.direction=4 
         self.left=wall.right 
       elif self.right>wall.left and self.centerx<wall.left and (self.centery<wall.ttopleft or self.centery>wall.bbottomright): 
        if self.direction==2: 
         self.direction=1 
         self.right=wall.left 
        if self.direction==4: 
         self.direction=3 
         self.right=wall.left 
     if self.top<0: 
      if self.direction==3: 
       self.direction=1 
       self.top=0 
      elif self.direction==4: 
       self.direction=2 
       self.topn=0 
     if self.bottom>winrect.bottom: 
      if self.direction==1: 
       self.direction=3 
       self.bottom=winrect.bottom 
      elif self.direction==2: 
       self.direction=4 
       self.bottom=winrect.bottom 
     if self.left<0: 
      if self.direction==1: 
       self.direction=2 
       self.left=0 
      elif self.direction==3: 
       self.direction=4 
       self.left=0 
     if self.right>winrect.right: 
      if self.direction==2: 
       self.direction=1 
       self.right=winrect.right 
      if self.direction==4: 
       self.direction=3 
       self.right=winrect.right 
     for box in boxes: 
      if box[0].collidepoint(self.center) and self.color==box[1]: 
       return True 
     return False 

#Game loop setup 
mode='title' 

#Game loop 
while True: 
    if mode=='title': 
     #event loop 
     for event in pygame.event.get(): 
      if event.type==pygame.QUIT: 
       pygame.quit() 
       sys.exit() 
      if event.type==pygame.MOUSEBUTTONDOWN: 
       if texts['start'][1].collidepoint(event.pos): 
        mode='levels' 
      if event.type==pygame.KEYDOWN: 
       if event.key==pygame.K_ESCAPE: 
        pygame.quit() 
        sys.exit() 
     #screen update 
     window.fill(GREEN) 
     mouse=pygame.mouse.get_pos() 
     if texts['start'][1].collidepoint(mouse): 
      window.blit(texts['start'][2], texts['start'][1]) 
     else: 
      window.blit(texts['start'][0], texts['start'][1]) 
     window.blit(texts['title'][0], texts['title'][1]) 
     pygame.display.update() 

    elif mode=='levels': 
     #event loop 
     for event in pygame.event.get(): 
      if event.type==pygame.QUIT: 
       pygame.quit() 
       sys.exit() 
      if event.type==pygame.MOUSEBUTTONDOWN: 
       for level in levels: 
        if level[3].collidepoint(event.pos) and level[4]!=0: 
         mode='loading' 
         loadinglevel=levels.index(level)+1 
      if event.type==pygame.KEYDOWN: 
       if event.key==pygame.K_ESCAPE: 
        pygame.quit() 
        sys.exit() 
     #screen update 
     window.fill(GREEN) 
     for level in levels: 
      if level[3].collidepoint(pygame.mouse.get_pos()) and level[4]==1: 
       window.blit(level[2], level[3]) 
      else: 
       window.blit(level[level[4]], level[3]) 
     window.blit(texts['levels'][0], texts['levels'][1]) 
     pygame.display.update() 

    elif mode=='loading': 
     if loadinglevel==1: 
      walls=[cwall(1, winrect.width/2, 100, winrect)] 
      balls=[] 
      for i in range(2): 
       balls.append(cball(20, 3, GREEN, winrect)) 
      for i in range(2): 
       balls.append(cball(20, 3, YELLOW, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/2), winrect.height), GREEN), (pygame.Rect(round(winrect.width/2), 0, round(winrect.width/2), winrect.height), YELLOW)) 
     elif loadinglevel==2: 
      walls=[cwall(1, winrect.width/2, 100, winrect)] 
      balls=[] 
      for i in range(4): 
       balls.append(cball(20, 3, GREEN, winrect)) 
      for i in range(4): 
       balls.append(cball(20, 3, YELLOW, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/2), winrect.height), GREEN), (pygame.Rect(round(winrect.width/2), 0, round(winrect.width/2), winrect.height), YELLOW)) 
     elif loadinglevel==3: 
      walls=[cwall(1, winrect.width/3, 100, winrect), cwall(1, 2*winrect.width/3, 100, winrect)] 
      balls=[] 
      for i in range(2): 
       balls.append(cball(20, 3, GREEN, winrect)) 
      for i in range(2): 
       balls.append(cball(20, 3, YELLOW, winrect)) 
      for i in range(2): 
       balls.append(cball(20, 3, BLUE, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/3), winrect.height), GREEN), (pygame.Rect(round(winrect.width/3), 0, round(winrect.width/3), winrect.height), YELLOW), 
        (pygame.Rect(round(2*winrect.width/3), 0, round(winrect.width/3), winrect.height), BLUE)) 
     elif loadinglevel==4: 
      walls=[cwall(1, winrect.width/3, 100, winrect), cwall(1, 2*winrect.width/3, 100, winrect)] 
      balls=[] 
      for i in range(4): 
       balls.append(cball(20, 3, GREEN, winrect)) 
      for i in range(4): 
       balls.append(cball(20, 3, YELLOW, winrect)) 
      for i in range(4): 
       balls.append(cball(20, 3, BLUE, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/3), winrect.height), GREEN), (pygame.Rect(round(winrect.width/3), 0, round(winrect.width/3), winrect.height), YELLOW), 
        (pygame.Rect(round(2*winrect.width/3), 0, round(winrect.width/3), winrect.height), BLUE)) 

     elif loadinglevel==7: 
      walls=[cwall(1, winrect.width/2, 100, winrect), cwall(0, winrect.height/2, 100, winrect)] 
      balls=[] 
      for i in range(2): 
       balls.append(cball(20, 3, GREEN, winrect)) 
      for i in range(2): 
       balls.append(cball(20, 3, YELLOW, winrect)) 
      for i in range(2): 
       balls.append(cball(20, 3, BLUE, winrect)) 
      for i in range(2): 
       balls.append(cball(20, 3, RED, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/2), round(winrect.height/2)), GREEN), 
        (pygame.Rect(0, round(winrect.height/2), round(winrect.width/2), round(winrect.height/2)), RED), 
        (pygame.Rect(round(winrect.width/2), 0, round(winrect.width/2), round(winrect.height/2)), YELLOW), 
        (pygame.Rect(round(winrect.width/2), round(winrect.height/2), round(winrect.width/2), round(winrect.height/2)), BLUE)) 
     elif loadinglevel==8: 
      walls=[cwall(1, winrect.width/2, 100, winrect), cwall(0, winrect.height/2, 100, winrect)] 
      balls=[] 
      for i in range(4): 
       balls.append(cball(20, 3, GREEN, winrect)) 
      for i in range(4): 
       balls.append(cball(20, 3, YELLOW, winrect)) 
      for i in range(4): 
       balls.append(cball(20, 3, BLUE, winrect)) 
      for i in range(4): 
       balls.append(cball(20, 3, RED, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/2), round(winrect.height/2)), GREEN), 
        (pygame.Rect(0, round(winrect.height/2), round(winrect.width/2), round(winrect.height/2)), RED), 
        (pygame.Rect(round(winrect.width/2), 0, round(winrect.width/2), round(winrect.height/2)), YELLOW), 
        (pygame.Rect(round(winrect.width/2), round(winrect.height/2), round(winrect.width/2), round(winrect.height/2)), BLUE)) 
     elif loadinglevel==5: 
      walls=[cwall(1, winrect.width/2, 100, winrect), cwall(0, winrect.height/2, 100, winrect)] 
      balls=[] 
      for i in range(10): 
       balls.append(cball(20, 3, RED, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/2), round(winrect.height/2)), RED), 
        (pygame.Rect(0, round(winrect.height/2), winrect.width, round(winrect.height/2)), WHITE), 
        (pygame.Rect(round(winrect.width/2), 0, round(winrect.width/2), winrect.height), WHITE)) 
     elif loadinglevel==6: 
      walls=[cwall(1, winrect.width/2, 100, winrect), cwall(0, winrect.height/2, 100, winrect)] 
      balls=[] 
      for i in range(20): 
       balls.append(cball(20, 3, RED, winrect)) 
      boxes=((pygame.Rect(0, 0, round(winrect.width/2), round(winrect.height/2)), RED), 
        (pygame.Rect(0, round(winrect.height/2), winrect.width, round(winrect.height/2)), WHITE), 
        (pygame.Rect(round(winrect.width/2), 0, round(winrect.width/2), winrect.height), WHITE)) 
     mode='playing' 
    elif mode=='playing': 
     while True: 
      #event loop 
      for event in pygame.event.get(): 
       if event.type==pygame.QUIT: 
        pygame.quit() 
        sys.exit() 
       if event.type==pygame.KEYDOWN: 
        if event.key==pygame.K_ESCAPE: 
         pygame.quit() 
         sys.exit() 
      #updates 
      updates=[] 
      for wall in walls: 
       wall.update() 
      for ball in balls: 
       updates.append(ball.update(winrect, walls)) 
      #Seeing if won 
      won=True 
      for update in updates: 
       if not update: 
        won=False 
        break 
      if won: 
       if levels[loadinglevel][4]==0: 
        levels[loadinglevel][4]=1 
       levels[loadinglevel-1][4]=2 
       mode='levels' 
       break 
      #blitting 
      window.fill(WHITE) 
      for box in boxes: 
       pygame.draw.rect(window, box[1], box[0]) 
      for wall in walls: 
       if wall.orientation==0: 
        pygame.draw.rect(window, BLACK, (wall.left, wall.top, wall.ttopleft, wall.height)) 
        pygame.draw.rect(window, BLACK, (wall.bbottomright, wall.top, wall.right-wall.bbottomright, wall.height)) 
       else: 
        pygame.draw.rect(window, BLACK, (wall.left, wall.top, wall.width, wall.ttopleft)) 
        pygame.draw.rect(window, BLACK, (wall.left, wall.bbottomright, wall.width, wall.bottom-wall.holesize)) 
      for ball in balls: 
       pygame.draw.circle(window, ball.color, ball.center, round(ball.width/2)) 
       pygame.draw.circle(window, BLACK, ball.center, round(ball.width/2), 2) 
      pygame.display.update() 
      pygame.time.Clock().tick(100) 
+0

Я бы предложил поставить вашу загрузку уровня в отдельные функции, чтобы улучшить удобочитаемость –

+0

@BartlomiejLewandowski Это, вероятно, поможет, но я сделал код, не зная, что он ответит на этот вопрос, и теперь мне не хочется его менять. – PygameNerd

+0

это просто совет для будущего :) –