2012-04-22 2 views
1

Heyo, это немного расширения в «импорте в рамках импорта» задает вопрос ранее меня, поэтому модераторы не стесняйтесь объединить 2.Python и Pygame: Избежание создавая поверхность дисплея дважды

У меня есть 2 файлы: A.py и B.py

#A.py 
import pygame 
import B 
pygame.init() 
tv = pygame.display.set_mode((256, 256)) 
tv.blit(<some surface here>) 


#B.py 
import pygame 
pygame.init() 
tv.blit()??? <--- I need to blit to tv, but how do I do it here? 

Я попытался сделать пустой файл с именем Globe и назначая глобальные значения для него, но большую часть времени я нашел это только делает мой код выглядеть неуклюжим и трудно писать. Также .. Я не хочу, чтобы init pygame дважды. Есть ли какой-нибудь «Pythonic» способ сделать это?

ответ

5

Этот вопрос может действительно применяться к любому структурированному приложению python.

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

Ваше приложение должно иметь одну точку входа. Предположим, что это будет A.py.
B.py будет библиотечным модулем, который вы будете импортировать и использовать его функции. Не стоит ожидать, что глобальная переменная tv будет работать. Вместо этого он должен иметь, по крайней мере, функции, которые принимают аргументы. Или даже класс, созданный с использованием поверхности. Преимущество такого подхода заключается в том, что ваш B модуля теперь повторно и не зависят от какого-то исполняемого основного сценария, обеспечивающего глобальной поверхность всегда называемой tv

B.py

def blitSpecial(surf): 
    surf.blit() 

A.py

import B 

tv = pygame.display.set_mode((256, 256)) 
B.blitSpecial(tv) 

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

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

+0

Хороший ответ. Но это действительно раздражает делать такие вещи, как: dostuff (tv, main, houses, building, people, tiles) – SuperDisk

+1

@SuperDisk: Согласен. Вот почему вы пытаетесь писать классы, которые создаются с помощью свойств. И методы работают над этими свойствами. Это был очень простой пример того, как писать модули. Как вы можете видеть во многих примерах pygame, люди подклассифицируют существующие классы для создания пользовательских материалов. Правильно, вам не нужно вызывать функцию с 10 аргументами. – jdi

0

Вам нужно только позвонить pygame.init() один раз, так что я думаю, что ваш код должен выглядеть следующим образом:

#A.py 
import pygame 
import B 

def setup(): 
    pygame.init() 
    tv = pygame.display.set_mode((256, 256)) 
    ... 
    mysurface = ... 
    tv.blit(mysurface) 
    return tv 


#B.py 
import pygame 
def mydraw(surface): 
    ... 
    surface.blit() 

# In whatever file you like :) 
if __name__ == '__main__': 
    surface_A = B.setup() # Do this first 
    mydraw(surface_A) 
+0

Я думаю, у вас есть несколько заметок здесь? 'setup()' находится в вашем 'A' модуле. Кроме того, документы говорят, что 'init' безопасно звонить несколько раз. – jdi

+0

Это/безопасно/для вызова нескольких раз, но не обязательно для этого. – snim2

+0

С точки зрения того, должна ли 'setup' быть в' A' или 'B', я думаю, что ваш ответ немного опрятен. Я оставил его в 'A', поскольку OP имел' display.set_mode' в своей 'A.py'. – snim2

0

Вы можете написать функции, принимающие объекты pygame.Surface в качестве параметров:

class TV(): 
    def __init__(self): 
     self.img = ... 

     ### insert code to load image here 

     self.rect = self.img.get_rect() 

    def draw(self, surface): 
     surface.blit(self.img, self.rect.topleft) 

    def erase(self, surface, background): 
     surface.blit(background, self.rect) 

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

Чтобы использовать его, просто создайте экран дисплея и телевизионный объект.

screen = pygame.display.set_mode((256, 256))  
background = pygame.Surface((0,0),(256,256)) 

background.fill(pygame.Color(0,0,0)) 
screen.fill(pygame.Color(0,0,0)) 

myTVobj = TV() 

Каждый раз, когда вы хотите сделать копию телевизора на экран вы звоните

myTVobj.draw(screen) 

Чтобы удалить объект, используйте

myTVobj.erase(screen, background) 

Затем вы можете сделать прикольные вещи позже с объектами, созданными из телевизионного класса, например, вставлять их в список.

tv_list = [] 
tv_list.append(myTVobj) 

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

tv_list = [] 
tv_list.append(myTVobj) 
tv_list.append(myTVobj) 
tv_list.append(myTVobj) 

for tv in tv_list: 
    tv.draw(screen) 

Или вы можете удалить их, просто изменив одну строку

for tv in tv_list: 
    tv.erase(screen) 

Наконец, вы можете добавить еще одну функцию к телевизору класса, что позволяет перемещать его. Если вы относитесь к правильному члену как к «маркеру позиции», все, что вам нужно сделать, это играть с его членами (хе-хе), чтобы изменить местоположение обновления на экране вашего объекта.

def move(self, move_amount=(1,0): 
    self.rect.move_ip(move_amount[0], move_amount[1])