简体   繁体   English

将对象从类转换为函数(Pygame)

[英]Blit object from a Class into a Function (Pygame)

some of you may have seen my previous questions regarding a Pygame project I'm currently working on, but I decided to do a rewrite and follow a proper object oriented programming since it wasn't really working out. 你们中的一些人可能已经看过我以前有关我目前正在从事的Pygame项目的问题,但是我决定重写并遵循正确的面向对象编程,因为它实际上并没有解决。

This is what I have so far: 这是我到目前为止的内容:

###### Import & Init ######
import pygame
import os, random, math, copy, sys

pygame.init()

###### Variables ######
displayWidth, displayHeight = 600, 600
shipWidth, shipHeight = 50, 50

# Variables that will be used to centre the ship.
startX = displayWidth / 2
startY = displayHeight - 40

screen = pygame.display.set_mode((displayWidth, displayHeight))
pygame.display.set_caption('Space Arcader')

####### Colours #######
# Colour list containing most common colours.
# Colour      R    G    B
red      = (255,   0,   0)
green    = (  0, 255,   0)
blue     = (  0,   0, 255)
grey     = (100, 100, 100)
black    = (  0,   0,   0)
white    = (255, 255, 255)
# Create a list from the colours in order to call it later.
colourList = [red, green, blue, black, white]

####### Classes #######
# Ship class
class Ship(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.image.load("assets/ship.png").convert_alpha()
        self.image = pygame.transform.scale(self.image,(shipWidth, shipHeight))
        self.transform = self.image

        self.rect = self.image.get_rect()
        self.rect.centerx = startX
        self.rect.centery = startY

        # Where the arrow will be pointing on game start
        self.angle = 90

    def update(self, direction):
        if direction == 'right' and self.angle > 20:
            self.angle -= 4
        elif direction == 'left' and self.angle < 160:
            self.angle += 4

        self.transform = pygame.transform.rotate(self.image, self.angle)
        self.rect = self.transform.get_rect()
        self.rect.centerx = startX
        self.rect.centery = startY

    def draw(self):
        screen.blit(self.transform, self.rect)

# Score class
class Score(object):
    def __init__(self):
        self.total = 0
        self.font = pygame.font.SysFont('Helvetica', 15)
        self.render = self.font.render('Score: ' + str(self.total), True, white)
        self.rect = self.render.get_rect()
        self.rect.left = 5
        self.rect.bottom = displayHeight - 2
        self.render.set_colorkey((0,0,0))

    def update(self, delete_scoreList):
        self.total += ((len(delete_scoreList)) * 50)
        self.render = self.font.render('Score: ' + str(self.total), True, white)

    def draw(self):
        screen.blit(self.render, self.rect)

# Game class
class MainGame(object):
    def __init__(self):
        self.score = 0
        self.game_over = False      

    def controls(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                Menu.terminate()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    direction = 'left'
                elif event.key == pygame.K_RIGHT:
                    direction = 'right'
            elif event.type == pygame.KEYUP:
                direction = None
                if event.key == pygame.K_SPACE:
                    bullet = Bullet()
                    bullet.rect.x = arrow.rect.x
                    bullet.rect.y = arrow.rect.y
                    all_sprites_list.add(bullet)
                    bulletList.add(bullet)
                elif event.key == pygame.K_ESCAPE:
                    running = False
                    MenuInit()

    def displayInit(self, screen):
        # Set screen width and height.
        display = pygame.display.set_mode((displayWidth, displayHeight))

        # Set the background image of the window.
        background = pygame.image.load("assets/background.jpg")

        # Blit the background onto the screen.
        screen.blit(background, (0, 0))

        # Disable mouse visibility.
        pygame.mouse.set_visible(False)

        # Code to redraw changing/moving objects.
        pygame.display.flip()

# Menu class
class Menu:
    hovered = False
    def __init__(self, text, pos):
        self.text = text
        self.pos = pos
        self.set_rect()
        self.draw()

    def draw(self):
        self.set_rend()
        screen.blit(self.rend, self.rect)

    def set_rend(self):
        menu_font = pygame.font.SysFont('Helvetica', 40)
        self.rend = menu_font.render(self.text, True, self.get_color())

    def get_color(self):
        if self.hovered:
            return (white)
        else:
            return (grey)

    def set_rect(self):
        self.set_rend()
        self.rect = self.rend.get_rect()
        self.rect.topleft = self.pos

    def terminate():
        pygame.quit()
        sys.exit()

####### Functions #######
def MenuInit():
    # Set the background image of the window.
    background = pygame.image.load("assets/menuBackground.jpg")

    options = [Menu("Start game", (200, 250)), Menu("Quit", (265, 300))]

    # Enable mouse visibility.
    pygame.mouse.set_visible(True) 

    while True:       
        for option in options:
            if option.rect.collidepoint(pygame.mouse.get_pos()):
                option.hovered = True
            else:
                option.hovered = False
            option.draw()

        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                for option in options:
                    if option.hovered and option.text == "Start game":
                        MainInit()
                    elif option.hovered and option.text == "Quit":
                        Menu.terminate()

        pygame.display.update()
        screen.blit(background,(0,0))

def MainInit():
    # Manage the refresh rate
    clock = pygame.time.Clock()

    # Loop the game until the user closes the application.
    running = True

    # Open an instance of the Game class
    game = MainGame()
    ship = Ship()
    score = Score()

    # Main Loop.
    while running:
        draw = ship.draw()
        ship.update(direction)
#        ship.update(direction)
#        ship.draw()
        controls = game.controls()
        game.displayInit(screen)

        # Refresh rate speed (frames per second).
        clock.tick(60)

# Open the menuInit() function which brings up the main menu.  
if __name__ == '__main__':
    MenuInit()

So my problem is trying to blit the ship and score onto the MainInit() function which calls the game class object as you can see above. 所以我的问题是试图弄乱飞船并得分到MainInit()函数上,该函数调用游戏类对象,如上所示。 Calling the game class object works fine because the background image changes and the controls work perfectly. 调用游戏类对象可以正常工作,因为背景图像会更改并且控件可以正常工作。 However, when I follow the same method for ship and score, it doesn't seem to work. 但是,当我采用相同的方法进行评分时,它似乎不起作用。 In the commented out comments, you can see I tried a few things but I got various errors such as "NameError: global name 'direction' is not defined" or NameError: global name 'update' is not defined 在注释掉的注释中,您可以看到我尝试了一些操作,但是遇到了各种错误,例如"NameError: global name 'direction' is not defined"NameError: global name 'update' is not defined "NameError: global name 'direction' is not defined" NameError: global name 'update' is not defined

Any pointers? 有指针吗? :) :)

Thank you very much. 非常感谢你。

The problem is caused by an out-of-scope variable - exactly as the error is telling you: global name 'direction' is not defined" . 问题是由范围外的变量引起的-正是错误告诉您: global name 'direction' is not defined"

You use direction in your def MainInit() , but direction is never defined in that function. 您可以使用direction在您的def MainInit()direction是从未在函数定义。 The place you define/set a direction -variable, is in class MainGame.controls() . 您定义/设置direction可变的位置位于class MainGame.controls()

The problem is, however, that the direction -variable created in class MainGame.controls() is local only. 问题是,然而,该direction在-variable创建class MainGame.controls()局部的 It will only exist within that specific function, MainGame.controls() . 它只会存在于该特定函数MainGame.controls() When that function is not used any longer, the value of direction will cease to exist - which is why there is no such thing as direction defined in def MainInit() . 当不再使用该函数时, direction的值将不复存在-这就是为什么在def MainInit()不存在诸如direction这样的东西的原因。 It's out of scope . 超出范围


To fix this problem, you can choose to use direction as a global variable. 若要解决此问题,您可以选择将direction用作全局变量。 It requires you to define the direction value outside any functions, so at the very beginning should work. 它要求您在任何功能之外定义direction值,因此一开始就应该起作用。

Whenever you want to read/modify that specific global variable, you should use the global keyword, to tell your Python function that you want to use/modify a global variable, and not a local one 每当您要读取/修改特定的全局变量时,都应该使用global关键字,以告诉您的Python函数您要使用/修改全局变量,而不是局部变量。

global direction

This might be of interest to you: https://stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-created-them 您可能对此很感兴趣: https : //stackoverflow.com/questions/423379/using-global-variables-in-a-function-other-than-the-one-that-c​​reated-them


Personally I would not use global variables, but rather store a direction member variable in the Ship -class and directly change that. 个人不会使用全局变量,而是将direction成员变量存储在Ship类中并直接对其进行更改。

Global variables can become quite a mess. 全局变量可能变得一团糟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM