Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!
  • Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • You can also use markdown to share your code. When using markdown your code will be automatically converted to BBCode. For help with markdown check out the markdown guide.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

Python I make a global variable and then it says it isn't defined, wtf? (Python / Pygame)

User8574

Active Coder
Python:
def ball_animation():
    global player_score

    player_score = 0

player_score_surf = font.render(str(player_score), False, (10,10,10))

Apparently player score is not defined. Please help! I tried taking it out of the function above it and it still doesn't work.
 
Python:
import random
import pygame, sys

def ball_restart():
    global ball_speed_x, ball_speed_y

    ball.center = (screen_width/2, screen_height/2)
    ball_speed_y *= random.choice((1,-1))
    ball_speed_x *= random.choice((1,-1))

def ball_animation():
    global ball_speed_x, ball_speed_y, player_score, opponent_score


    #here is where it is defined
    
    player_score = 0
    opponent_score = 0

    ball.x += ball_speed_x
    ball.y += ball_speed_y

    if ball.top <= 0 or ball.bottom >= screen_height:
        ball_speed_y *= -1
    if ball.left <= 0:
        player_score += 1
        ball_restart()
    if ball.right >= screen_width:
        opponent_score += 1
        ball_restart()

    if ball.colliderect(player) or ball.colliderect(opponent):
        ball_speed_x *= -1

pygame.init()
clock = pygame.time.Clock()

screen_width = 1280
screen_height = 960
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption("Pong")

ball = pygame.Rect(screen_width/2 - 15, screen_height/2 - 15, 30,30)
player = pygame.Rect(screen_width - 20, screen_height/2 - 70, 10,140)
opponent = pygame.Rect(10, screen_height/2 - 70, 10,140)

font = pygame.font.Font(None, 100)

# here is where the error comes up
player_score_surf = font.render(str(player_score), False, (10,10,10))

bg_color = pygame.Color("white")
black = pygame.Color("black")

ball_speed_x = 7
ball_speed_y = 7
player_speed = 0
opponent_speed = 7

while True:
    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_UP:
                player_speed -=7

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_DOWN:
                player_speed +=7

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_UP:
                player_speed +=7

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_DOWN:
                player_speed -=7

    ball_animation()

    # Player

    player.y += player_speed

    if player.top <= 0:
        player.top = 0
    if player.bottom >= screen_height:
        player.bottom = screen_height

    # Opponent

    if opponent.top < ball.y:
        opponent.top += opponent_speed
    if opponent.bottom > ball.y:
        opponent.bottom -= opponent_speed

    if opponent.top <= 0:
        opponent.top = 0
    if opponent.bottom >= screen_height:
        opponent.bottom = screen_height

    screen.fill(bg_color)
    pygame.draw.rect(screen, black, player)
    pygame.draw.rect(screen, black, opponent)
    pygame.draw.ellipse(screen, black, ball)
    pygame.draw.aaline(screen, black, (screen_width/2,0), (screen_width/2, screen_height))
    screen.blit(player_score_surf, (200,200))

    pygame.display.flip()
    clock.tick(60)
 
I tried doing that and this came up.

pygame 2.1.2 (SDL 2.0.18, Python 3.10.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:\Users\qwegef\PycharmProjects\pygamegames\reference.py", line 78, in <module>
ball_animation()
TypeError: ball_animation() missing 2 required positional arguments: 'player_score' and 'opponent_score'

Process finished with exit code 1


For context I moved them right to the top of the code after the import random and import pygame code.
 
TypeError: ball_animation() missing 2 required positional arguments: 'player_score' and 'opponent_score'
Seems like in the meantime you have added parameters to that function ? That seems to change the game a bit.

Actually the real issue is that you are referencing player_score before you call ball_animation() so it has no value yet.
Python lamely spits out "not defined" when you have not assigned a value, as demonstrated by this code

Python:
def myfunc():
    global player_score
    player_score = 0
print(str(player_score))

which gives the same error.

This code works:
Python:
def myfunc():
    global player_score
    player_score = 0
myfunc()
print(str(player_score))

I don't see the point of declaring a variable inside a function and then marking it global to let everybody access it. It goes against all rules of accepted programming practice. Why the Python designers thought this was something the language needed is beyond me. I'm not at all against globals (as opposed to passing a value through umpteen levels of functions) but for heaven's sake define them on the global level. Doing it like this seems like so much obfuscation to me.
 
I tried doing that and this came up.

pygame 2.1.2 (SDL 2.0.18, Python 3.10.9)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:\Users\qwegef\PycharmProjects\pygamegames\reference.py", line 78, in <module>
ball_animation()
TypeError: ball_animation() missing 2 required positional arguments: 'player_score' and 'opponent_score'

Process finished with exit code 1


For context I moved them right to the top of the code after the import random and import pygame code.
If you're getting the missing positional arguments error, it means that you've also changed the actual ball_animation() function to now accept two parameters. This error is a good indicator that you're taking steps towards removing your use of globals (woop woop!)

You just need to remember that by having ball_animation() take in two parameters (i.e. the player and opponent score), you'll also need to place those two values into any function call that happens.

Take a look at line 78; chances are you call the function but don't actually provide the two values it needs to run. :))
 
If you're getting the missing positional arguments error, it means that you've also changed the actual ball_animation() function to now accept two parameters. This error is a good indicator that you're taking steps towards removing your use of globals (woop woop!)
Yes. Although that wasn't actually the solution to the problem. Even if a global is on the global level, you still need to give it a value to avoid the 'not defined' error, as shows this code :

Python:
global player_score
print(str(player_score))

IMHO Python is really lame with this error message. If only it had been "Variable not initialized" this whole discussion would have been unnecessary. In Python speak, defining seems to be the same as initializing. Perhaps it makes sense as there is actually no syntax to declare a variable, like in any decent language. They just had to be different, didn't they 🍥
 
Yes. Although that wasn't actually the solution to the problem. Even if a global is on the global level, you still need to give it a value to avoid the 'not defined' error, as shows this code :

Python:
global player_score
print(str(player_score))

IMHO Python is really lame with this error message. If only it had been "Variable not initialized" this whole discussion would have been unnecessary. In Python speak, defining seems to be the same as initializing. Perhaps it makes sense as there is actually no syntax to declare a variable, like in any decent language. They just had to be different, didn't they 🍥
Without a doubt, Python has never been a language I've been fond of, specifically when it comes to how it tries to be unique. Whenever I teach people about Python and how to use it, I'll always slide in the joke that "This is completely different to other languages because Python wants to be special".

The only suitable time I'll use Python is in technical interviews where I need to get a solution as quickly as possible.
 
Without a doubt, Python has never been a language I've been fond of, specifically when it comes to how it tries to be unique. Whenever I teach people about Python and how to use it, I'll always slide in the joke that "This is completely different to other languages because Python wants to be special".

The only suitable time I'll use Python is in technical interviews where I need to get a solution as quickly as possible.
 
I recognize the power of Python, but indeed that's my main bone with it too. Nonetheless, being so different apparently hasn't stopped it from becoming the most used programming language ! And I half wonder whether it makes sense. If you know a couple of languages that are very much alike, but all have their subtle differences, that can be quite annoying. When I first started with C# I had trouble not automatically writing Java commands like System.out.println, and I am still baffled by their random differences in capitalization (toString vs ToString for example). Now that I hardly use Java anymore, I struggle not to write console.log() in C# 😂
 
Here is my attempt at your project. Still working on ball animation and scoring and collide points


Updated code. Task left - work on the scoring and have computer player chase the ball instead of just going up and down.
Python:
# Do the imports
from random import choice
import pygame
# Initiate pygame
pygame.init()
# Setup pygame clock and frame rate
clock = pygame.time.Clock()
fps = 60
# Set screen size
screen_size = (1280, 960)
# Create the screen
screen = pygame.display.set_mode(screen_size)
# Create the window caption
pygame.display.set_caption('Pong')
# Empty list for players
players = []
# Create the player class
class Player:
    '''
        The player class needs x and y coords for posion
        Computer is set for default name for pc player.
    '''
    def __init__(self, x, y, name='Computer'):
        '''
            Create player attributes. Create player surface,
            x and y coords, name, score (default 0), player speed, get player rect,
            and a starting direction.
            append player to players list
        '''
        self.x = x
        self.y = y
        self.name = name
        self.score = 0
        self.speed = 7
        self.direction = 1
        players.append(self)
    # Draw the player
    def draw(self):
        self.player = pygame.Rect(self.x, self.y, 10, 100)
        self.rect = pygame.draw.rect(screen, 'black', self.player)
        
    # Show player score
    def show_score(self):
        font = pygame.font.SysFont(None, 24)
        text = font.render(f'{self.name}: {self.score}', True, 'white')
        textRect = text.get_rect()
        textRect.center = (self.x//2, 10,)
        if self.name == 'Computer':
            screen.blit(text, (textRect[0]+textRect[0]/2, 10))
        else:
            screen.blit(text, ((screen_size[0]/4)-textRect[0], 10))
   
    # Update player movement
    def update(self):
        keys = pygame.key.get_pressed()
        # If statement is for human player
        if self.name != 'Computer':
            if keys[pygame.K_UP]:
                self.y -= self.speed
                if self.y <= 40:
                    self.y = 40
            if keys[pygame.K_DOWN]:
                self.y += self.speed
                if self.y >= screen_size[1] - 100:
                    self.y = screen_size[1] - 100
        # Else for computer player
        else:
            self.y = self.y + self.speed * self.direction
            if self.y <= 40:
                self.y = 40
                self.direction = 1
            if self.y >= screen_size[1] - 100:
                self.y = screen_size[1] - 100
                self.direction = -1
                
# Create a Ball class           
class Ball:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.velocity = [5, 5]
        self.hidden = False
        self.hide_timer = pygame.time.get_ticks()
    
    # Hide the ball and set timer if past boundry
    def hide(self):
        self.hidden = True
        self.hide_timer = pygame.time.get_ticks()
        
    # Draw the ball
    def draw(self):
        self.ball = pygame.Rect(self.x, self.y, 25, 25)
        self.rect = pygame.draw.ellipse(screen, 'blue', self.ball)
    # Define the ball animations
    def animation(self):
        # Resets the ball after 3 seconds
        if self.hidden and pygame.time.get_ticks() - self.hide_timer > 3000:
            self.hidden = False
            self.x = screen_size[0]/2-12.5
            self.y = screen_size[1]/2
            
        # Set ball velocity for up and down
        self.x -= self.velocity[0]
        self.y += self.velocity[1]
        # Right side of ball is less than 0, hide the ball
        if self.ball.right+5 < 0:
            self.hidden = True
            
        # Left side of ball has passed screen width, hide ball
        if self.ball.left > screen_size[0]+5:
            self.hidden = True
            self.x += self.velocity[0]
        # Bounce ball off the top and bottom walls
        if self.ball.top <= 40:
            self.velocity[1] = 5
        if self.ball.bottom >= screen_size[1]:
            self.velocity[1] = -5
    # Detect if ball hits player paddle
    def collision(self, player):
        if self.ball.colliderect(player):
            if player.name == 'Computer':
                self.velocity[0] = 5
            else:
                self.velocity[0] = -5

# Create the players. Player could be any name. Set to Player as not to have two Computer players
player1 = Player(10, screen_size[1]/2-50, 'Player')
player2 = Player(screen_size[0]-20, screen_size[1]/2-50)
ball = Ball(screen_size[0]/2-12.5, screen_size[1]/2)


running = True
while running:
    screen.fill('white')
    event = pygame.event.poll()
    if event.type == pygame.QUIT:
        running = False
    # Create the dark area at top for holding score text
    pygame.draw.rect(screen, pygame.Color(90,90,90), pygame.Rect(0, 0, screen_size[0], 40))
    # The line in the middle
    pygame.draw.aaline(screen, 'black', (screen_size[0]/2, 0), (screen_size[0]/2, screen_size[1]))
    # Create and draw the ball
    ball.draw()
    ball.animation()
    # Show all players, data, and updates
    for player in players:
        player.show_score()
        player.draw()
        player.update()
        ball.collision(player)
    pygame.display.flip()
    clock.tick(60)
 
Last edited:
Finished code with comments

Python:
# Do the imports
from random import randint
import pygame

# Initiate pygame
pygame.init()

# Setup pygame clock and frame rate
clock = pygame.time.Clock()
fps = 60

# Set screen size
screen_size = (1280, 960)

# Create the screen
screen = pygame.display.set_mode(screen_size)

# Create the window caption
pygame.display.set_caption('Pong')

# Empty list for players
players = []

# Create the player class
class Player:
    '''
        The player class needs x and y coords for posion
        Computer is set for default name for pc player.
    '''
    def __init__(self, x, y, name='Computer', ball_pos=0.0):
        '''
            Create player attributes. Create player surface,
            x and y coords, name, score (default 0), player speed, get player rect,
            and a starting direction.
            append player to players list
        '''
        self.x = x
        self.y = y
        self.name = name
        self.score = 0
        self.speed = 7
        self.direction = 1
        self.ball_pos = ball_pos

        players.append(self)

    # Draw the player
    def draw(self):
        self.player = pygame.Rect(self.x, self.y, 10, 100)
        self.rect = pygame.draw.rect(screen, 'black', self.player)
        
    # Show player score
    def show_score(self):
        font = pygame.font.SysFont(None, 24)
        text = font.render(f'{self.name}: {self.score}', True, 'white')
        textRect = text.get_rect()
        textRect.center = (self.x//2, 10,)
        if self.name == 'Computer':
            screen.blit(text, (textRect[0]+textRect[0]/2, 10))
        else:
            screen.blit(text, ((screen_size[0]/4)-textRect[0], 10))
  
    # Update player movement
    def update(self):
        keys = pygame.key.get_pressed()

        # If statement is for human player
        # Moves paddle with up and down keys or w and s keys
        if self.name != 'Computer':
            if keys[pygame.K_UP] or keys[pygame.K_w]:
                self.y -= self.speed
                if self.y <= 40:
                    self.y = 40

            if keys[pygame.K_DOWN] or keys[pygame.K_s]:
                self.y += self.speed
                if self.y >= screen_size[1] - 100:
                    self.y = screen_size[1] - 100

        # Else for computer player
        else:
            # Set speed and direction of computer paddle
            self.y = self.y + self.speed * self.direction

            # Track ball position and move paddle toward ball if moving down to bottom
            if self.y > self.ball_pos:
                self.direction = -0.85

            # Set boundry for bottom so paddle doesn't leave the playing field
            if self.y >= screen_size[1] - 100:
                self.y = screen_size[1] - 100
            
            # Track ball position and move paddle toward ball if moving to top
            if self.y < self.ball_pos:
                self.direction = 0.85
            
            # Set paddle boundry for top of field so paddle doesn't leave playing field
            if self.y <= 40:
                self.y = 40
                
          

                
# Create a Ball class           
class Ball:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.velocity = [5, 5]

    # Draw the ball
    def draw(self):
        self.ball = pygame.Rect(self.x, self.y, 25, 25)
        self.rect = pygame.draw.ellipse(screen, 'blue', self.ball)

    # Define the ball animations
    def animation(self):
        # Set ball velocity for up and down
        self.x -= self.velocity[0]
        self.y += self.velocity[1]

        # If left or right side of ball hits left or right boundry then bounce ball
        # randint sets a random speed for ball after bounce
        if self.ball.left <= 0:
            self.velocity[0] = -randint(5, 8)

        if self.ball.right >= screen_size[0]:
            self.velocity[0] = randint(5, 8)
            
        # Bounce ball off the top and bottom walls
        if self.ball.top <= 40:
            self.velocity[1] = randint(5, 8)
        if self.ball.bottom >= screen_size[1]:
            self.velocity[1] = -randint(5, 8)

    # Detect if ball hits player paddle
    def collision(self, player):
        if self.ball.colliderect(player):
            if player.name == 'Computer':
                self.velocity[0] = randint(5,8)
            else:
                self.velocity[0] = -randint(5, 8)


# Create the players. Player could be any name.
# Default name is computer
# Set to Player as not to have two Computer players
player1 = Player(10, screen_size[1]/2-50, 'Player')
player2 = Player(screen_size[0]-20, screen_size[1]/2-50)
ball = Ball(screen_size[0]/2-12.5, screen_size[1]/2)


running = True
while running:
    screen.fill('white')

    event = pygame.event.poll()
    if event.type == pygame.QUIT:
        running = False

    # Create the dark area at top for holding score text
    pygame.draw.rect(screen, pygame.Color(90,90,90), pygame.Rect(0, 0, screen_size[0], 40))

    # The line in the middle
    pygame.draw.aaline(screen, 'black', (screen_size[0]/2, 0), (screen_size[0]/2, screen_size[1]))

    # Create and draw the ball
    ball.draw()
    ball.animation()

    # Show all players, data, and updates
    for player in players:
        player.show_score()
        player.draw()
        player.update()
        ball.collision(player)
        player.ball_pos = ball.y

    if ball.x <= -5:
        player2.score += 1
    if ball.x >= screen_size[0]-20:
        player1.score += 1

    pygame.display.flip()
    clock.tick(60)
 

New Threads

Latest posts

Buy us a coffee!

Back
Top Bottom