Reputation: 23
The following code from a game engine I'm tinkering in gives me this error:
***"UnboundLocalError: local variable 'event' referenced before assignment":***
player.update(current_level.object_list, event) found in the main_loop() in line 342
main_loop() in line 364.
The only thing I try to do here is to transition from the red intro screen to the main loop by pressing return.
The engine itself ran fine until I made the game_intro()
function and positioned it before the main_loop()
function to run at the last couple of lines. I tried to play around with the 2 functions themselves to see what could make it work but no luck. Also placing event = None in line 340 above the player.update statement in line 339 allows me to transition from the intro to the main loop but the movement controls stop working.
I am pretty sure the error has to do something with the update() function in the Player class, but have no clue what causes it, especially when the intro function doesn't use event that's used in the update function (apart from pygame.event) and it only started crashing after adding the intro screen.
from pygame import *
import pygame
# from colours import *
# from textObjects import small, medium, large
black = pygame.Color(0, 0, 0)
white = pygame.Color(255, 255, 255)
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
blue = pygame.Color(0, 0, 255)
pygame.font.init()
small = pygame.font.SysFont(None, 25)
medium = pygame.font.SysFont(None, 50)
large = pygame.font.SysFont(None, 80)
class Player(pygame.sprite.Sprite):
# Initialise function
def __init__(self, color=blue, width=32, height=48, health=100):
# I assume super() inherits everything from the block class
super(Player, self).__init__()
# Set the image to a Surface of size width and height
self.image = pygame.Surface((width, height))
# Fill the image with the default color of blue
self.image.fill(color)
# Use the Surface of the image to get the rectangular co-ordinates
self.set_properties()
# Create speed for x and y
self.speed_x = 0
self.speed_y = 0
# Create health
self.health = 100
self.level = None
def set_properties(self):
self.rect = self.image.get_rect()
# Create an x and y origin position (Centered the mouse on the sprite)
self.origin_x = self.rect.centerx
self.origin_y = self.rect.centery
self.speed = 5
# Create total travel distance to check the player's position on the map
self.travel_distance_x = 0
self.travel_distance_y = 0
# Function to easily set the position of any block object on the center
def set_position(self, x, y):
self.rect.x = x - self.origin_x
self.rect.y = y - self.origin_y
# Function made to print the position on the map
def print_position(self):
self.travel_distance_x += self.speed_x
self.travel_distance_y += self.speed_y
print self.travel_distance_x, self.travel_distance_y
def set_level(self, level):
self.level = level
self.set_position(level.player_start_x, level.player_start_y)
def set_image(self, filename=None):
if filename != None:
self.image = pygame.image.load(filename).convert()
self.set_properties()
def death(self):
print "Kill"
return display_message("Vaziuojam", black)
def update(self, collidable=pygame.sprite.Group(), event=True):
self.experience_gravity()
self.event = True
self.rect.x += self.speed_x
collision_list = pygame.sprite.spritecollide(self, collidable, False)
for collided_object in collision_list:
# Right direction
if self.speed_x > 0:
self.rect.right = collided_object.rect.left
# Left direction
elif self.speed_x < 0:
self.rect.left = collided_object.rect.right
self.rect.y += self.speed_y
collision_list = pygame.sprite.spritecollide(self, collidable, False)
for collided_object in collision_list:
# Down direction
if self.speed_y > 0:
self.rect.bottom = collided_object.rect.top
self.speed_y = 0
# Up direction
elif self.speed_y < 0:
self.rect.top = collided_object.rect.bottom
self.speed_y = 0
if not event == None:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
self.speed_x = -self.speed
# self.change_speed(-self.speed, 0)
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
self.speed_x = self.speed
# self.change_speed(self.speed, 0)
if event.key == pygame.K_UP or event.key == pygame.K_w:
if len(collision_list) >= 1:
self.speed_y = -(self.speed) * 2
# self.change_speed(0, -self.speed * 2)
if event.key == pygame.K_DOWN:
# self.change_speed(0, self.speed)
pass
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_a:
if self.speed_x < 0:
self.speed_x = 0
if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
if self.speed_x > 0:
self.speed_x = 0
def experience_gravity(self, gravity=0.35):
if self.speed_y == 0:
self.speed_y = 1
else:
self.speed_y += gravity
class Block(pygame.sprite.Sprite):
def __init__(self, x, y, width, height, color=blue):
# I assume super() inherits everything from the block class
super(Block, self).__init__()
# Set the image to a Surface of size width and height
self.image = pygame.Surface((width, height))
# Fill the image with the default color of blue
self.image.fill(color)
# Get rectangle object of the block
self.rect = self.image.get_rect()
# Assign x and y co-ordinates of the block
self.rect.x = x
self.rect.y = y
def experience_gravity(self, gravity=0.35):
if self.speed_y == 0:
self.speed_y = 1
else:
self.speed_y += gravity
class Level(object):
def __init__(self, player_object):
self.object_list = pygame.sprite.Group()
self.player_object = player_object
self.player_start = self.player_start_x, self.player_start_y = 80, 150
self.world_shift_x = 0
self.world_shift_y = 0
self.left_viewbox = screen_width / 2 - screen_width / 8
self.right_viewbox = screen_width / 2 + screen_width / 8
self.up_viewbox = screen_height / 3
self.down_viewbox = screen_height / 2 # + screen_height / 12
def update(self):
self.object_list.update()
def draw(self, screen):
screen.fill(white)
self.object_list.draw(screen)
def shift_world(self, shift_x, shift_y):
self.world_shift_x += shift_x
self.world_shift_y += shift_y
for each_object in self.object_list:
each_object.rect.x += shift_x
each_object.rect.y += shift_y
def scroll(self):
if self.player_object.rect.x <= self.left_viewbox:
view_difference = self.left_viewbox - self.player_object.rect.x
self.player_object.rect.x = self.left_viewbox
self.shift_world(view_difference, 0)
if self.player_object.rect.x >= self.right_viewbox:
view_difference = self.right_viewbox - self.player_object.rect.x
self.player_object.rect.x = self.right_viewbox
self.shift_world(view_difference, 0)
if self.player_object.rect.y <= self.up_viewbox:
view_difference = self.up_viewbox - self.player_object.rect.y
self.player_object.rect.y = self.up_viewbox
self.shift_world(0, view_difference)
if self.player_object.rect.y >= self.down_viewbox:
view_difference = self.down_viewbox - self.player_object.rect.y
self.player_object.rect.y = self.down_viewbox
self.shift_world(0, view_difference)
class Level_01(Level):
def __init__(self, player_object):
super(Level_01, self).__init__(player_object)
level = [
#[x, y, width, height, color]
[0, 3, 10, 844, black],
[108, 0, 21, 730, black],
[5, 838, 325, 9, black],
[240, 815, 130, 32, black],
[316, 782, 204, 64, black],
[364, 749, 179, 96, black],
[469, 680, 84, 156, black],
[365, 805, 189, 42, black],
[410, 715, 68, 56, black],
[645, 679, 244, 18, black],
[977, 678, 265, 13, black],
[1439, 676, 93, 14, black],
[1668, 670, 222, 16, black],
[2068, 664, 359, 18, black],
[2544, 617, 11, 64, black],
[2653, 556, 11, 80, black],
[2771, 484, 15, 113, black],
[2922, 434, 277, 12, black],
[2777, 327, 138, 15, black],
[2659, 242, 20, 126, black],
[2505, 178, 17, 145, black],
[2226, 257, 176, 14, black],
[2120, 266, 10, 92, black],
[1808, 252, 213, 10, black],
[1631, 265, 8, 86, black],
[1231, 255, 293, 14, black],
[1009, 261, 169, 12, black],
[670, 259, 189, 18, black],
[116, 127, 420, 20, black],
[590, 183, 19, 95, black]
]
for block in level:
block = Block(block[0], block[1], block[2], block[3], block[4])
self.object_list.add(block)
def set_message(text):
global message, previous_message
message = font.render(text, True, black, white)
previous_message = message
def text_objects(text, color, size):
if size == 'small':
textSurface = small.render(text, True, color)
if size == 'medium':
textSurface = medium.render(text, True, color)
if size == 'large':
textSurface = large.render(text, True, color)
return textSurface, textSurface.get_rect()
def display_message(text, color, y_displacement=0, size='small'):
textSurface, textRectangle = text_objects(text, color, size)
textRectangle.center = (screen_width / 2), (screen_height / 2) + y_displacement
screen.blit(textSurface, textRectangle)
def character_message(text, color, y_displacement=0, size='small'):
textSurface, textRectangle = text_objects(text, color, size)
textRectangle = player.travel_distance_x , player.travel_distance_y + y_displacement
screen.blit(textSurface, textRectangle)
# Initialise pygame module
pygame.init()
# Initialise pygame font
pygame.font.init()
# Defining the screen size
screen_size = screen_width, screen_height = 800, 600
# Setting the display and getting the Surface object
screen = pygame.display.set_mode(screen_size)
# Getting the Clock object
clock = pygame.time.Clock()
# Setting a title to the window
pygame.display.set_caption("TODO make title")
# Defining variable for FPS
fps_limit = 60
# Clear the screen
screen.fill(white)
# Setting the FPS at which the game will run
clock.tick(fps_limit)
# Group all the currently active objects
active_object_list = pygame.sprite.Group()
# Set variable player to the Player() class
player = Player()
# Add player to the active object list
active_object_list.add(player)
# Make a list for the levels and append Level_01 to that list with player as the handler
level_list = []
level_list.append(Level_01(player))
current_level_number = 0
current_level = level_list[current_level_number]
player.set_level(current_level)
# Define our font
font = pygame.font.SysFont(None, 25)
# Define a message, we're doing this because it will be used as a surface
message = previous_message = None
set_message("")
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
run=True
intro=False
if event.key == pygame.K_ESCAPE:
pygame.quit()
quit()
screen.fill(red)
pygame.display.update()
def main_loop():
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
run = False
# Update functions
player.update(current_level.object_list, event)
event = None
current_level.update()
# Logic testing
current_level.scroll()
# Draw everything
current_level.draw(screen)
active_object_list.draw(screen)
if player.travel_distance_y > 900:
player.health = 0
display_message("Death test message", black)
# Delay fps
clock.tick(fps_limit)
# Update screen
pygame.display.update()
player.print_position()
game_intro()
main_loop()
I'm still trying only starting to comprehend classes and scopes so any tips would be a huge help, thank you in advance!
Upvotes: 0
Views: 78
Reputation: 3495
As mentioned by molbdnilo, the indentation was wrong in the main loop. However, once you pass in the event, it's fine, but if there is no event, the player doesn't update.
The better way around this would be to make a global variable for events, then run the update function once per frame, and inside that check for events, but as to a quick fix, here you go.
def main_loop():
run = True
while run:
current_events = pygame.event.get()
if current_events:
for event in current_events:
if event.type == pygame.QUIT:
pygame.quit()
quit()
run = False
# Update functions
player.update(current_level.object_list, event)
current_level.update()
else:
player.update(current_level.object_list, None)
current_level.update()
# Logic testing
current_level.scroll()
# Draw everything
current_level.draw(screen)
active_object_list.draw(screen)
if player.travel_distance_y > 900:
player.health = 0
display_message("Death test message", black)
# Delay fps
clock.tick(fps_limit)
# Update screen
pygame.display.update()
player.print_position()
Upvotes: 1