Reputation: 147
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.
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. 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
Any pointers? :)
Thank you very much.
Upvotes: 0
Views: 1436
Reputation: 618
The problem is caused by an out-of-scope variable - exactly as the error is telling you: global name 'direction' is not defined"
.
You use direction
in your def MainInit()
, but direction
is never defined in that function. The place you define/set a direction
-variable, is in class MainGame.controls()
.
The problem is, however, that the direction
-variable created in class MainGame.controls()
is local only. It will only exist within that specific function, 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()
. It's out of scope.
To fix this problem, you can choose to use direction
as a global variable. It requires you to define the direction
value outside any functions, so at the very beginning should work.
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 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
Personally I would not use global variables, but rather store a direction
member variable in the Ship
-class and directly change that.
Global variables can become quite a mess.
Upvotes: 1