I wanted to create a button module separate from my main file for my game. It runs okay in isolation. But the issue comes when I want to reference it in the main file as it either does not show on the screen at all (with no error message) or it will indefinitely call itself.
import pygame
class button:
def init(self, width, height, position = [], clr=[100, 100, 100], cngclr=None, func=None, text='', font_clr = (0, 0, 0), font="Courier New", font_size=16):
width = int(width)
height = int(height)
size = (width, height)
self.clr = clr
self.size = size
self.func = func
self.surf = pygame.Surface(size)
self.rect = self.surf.get_rect(center=position)
if cngclr:
self.cngclr = cngclr
else:
self.cngclr = clr
if len(clr) == 4:
self.surf.set_alpha(clr[3])
self.font = pygame.font.SysFont(font, font_size)
self.txt = text
self.font_clr = font_clr
self.txt_surf = self.font.render(self.txt, 1, self.font_clr)
self.txt_rect = self.txt_surf.get_rect(center=[wh//2 for wh in self.size])
def draw(self, screen):
self.mouseover()
self.surf.fill(self.curclr)
self.surf.blit(self.txt_surf, self.txt_rect)
screen.blit(self.surf, self.rect)
def mouseover(self):
#what happens when the mouse hovers over the button
self.curclr = self.clr
pos = pygame.mouse.get_pos()
#colour changes to cng_clr
if self.rect.collidepoint(pos):
self.curclr = self.cngclr
def call_back(self, *args):
if self.func:
return self.func(*args)
class text:
def __init__(self, msg, position, clr=[100, 100, 100], font="Courier New", font_size=15, mid=False):
self.position = position
self.font = pygame.font.SysFont(font, font_size)
self.txt_surf = self.font.render(msg, 1, clr)
if len(clr) == 4:
self.txt_surf.set_alpha(clr[3])
if mid:
self.position = self.txt_surf.get_rect(center=position)
def draw(self, screen):
screen.blit(self.txt_surf, self.position)
# call back functions
def fn1():
print('button1')
def fn2():
print('button2')
if __name__ == '__main__':
pygame.init()
screen_size = (300, 200)
size = 10
clr = [255, 0, 255]
bg = (255, 255, 0)
font_size = 15
font = pygame.font.Font(None, font_size)
clock = pygame.time.Clock()
screen = pygame.display.set_mode(screen_size)
screen.fill(bg)
button1 = button(position=[80, 100], width = 100, height = 50, clr=(220, 220, 220),
cngclr=(255, 0, 0), func=fn1, text='button1', font_clr = (200, 10, 10))
button2 = button((220, 100), (100, 50), (220, 220, 220), (255, 0, 0), fn2, 'button2', font_clr = (100, 100,100))
button_list = [button1, button2]
crash = True
while crash:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crash = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
crash = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
for b in button_list:
if b.rect.collidepoint(pos):
b.call_back()
pygame.display.update()
clock.tick(60)
This is how I call it in the main file. With this code, the buttons do not even show on the screen.
playButton = button(position = (60, 300), width = 100, height = 50, clr = blue, cng_clr = lightBlue, func = Game.startScreen(self, enteredUsername, cow), text ='Play', font_clr = orange)
#this button allows the user to see account details and allows user to change
#password, see their high score etc.
accountButton = button(position = (180, 300), width = 250, height = 50, clr = blue, cng_clr = lightBlue, func = Game.accountDetails(self, enteredUsername), text = 'Account Details', font_clr = orange)
#this creates a quit button that closes the game window only
quitButton = button(position = (450, 300), width = 100, height = 50, clr = blue, cng_clr = lightBlue, func = Game.quitGame(self), text = 'Quit', font_clr = orange)
buttonList = [playButton, accountButton, quitButton]
crash = True
while crash:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crash = False
elif event.type == pygame.KEYDOWN:
#if event.key == pygame.K_ESCAPE:
crash = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
#this makes the function work
for b in buttonList:
if b.rect.collidepoint(pos):
b.call_back()
#draws all the buttons on a particular page
for b in buttonList:
b.draw(gameDisplay)
pygame.display.update()
However, when I call the pause button. It causes the program to crash and says max recursion depth has been reached.
The code is this:
global pauseButton
pauseButton = button(position = (560, 10), width = 30, height = 30, clr = lightOrange, cng_clr = orange, func = Game.pause(self, enteredUsername), text = "||")
#this creates a cow object
buttonList = [pauseButton,]
self.mode = ""
Game.setMode(self, enteredUsername)
mode = self.mode
global cow
cow = player(225, 325, 150, 142)
#cow.setSprite(self, 'blue')
overPause = False
global score
score = 0
run = True
#sets the speed of animation
speed = 180
#creates an array to put the obstacles in
#allows for random generation of obstacles
global obstacles
obstacles = []
#this sets the amount of time between each instance of an obstacle
#the shorter amount of time the more obstacles generated
cow.hit = False
lowestSpeed = 2500
highestSpeed = 3500
pygame.time.set_timer(USEREVENT+2, random.randrange(lowestSpeed, highestSpeed))
#the main loop
while run:
while cow.scoreAddition != 0:
score += 100
cow.scoreAddition = 0
score += 1
pygame.display.update()
#this means the obstacles will appear in the three rows randomly
x = [140, 270, 395]
randomNo = random.randint(0,2)
redrawGameWindow(None,score, enteredUsername, None, mode)
clock.tick(speed)
#this allows for the scrolling background
bgY -= 2.8 #1.4
bgY2 -= 2.8 #1.4
if bgY < bg.get_height() * -1:
bgY = bg.get_height()
if bgY2 < bg.get_height() * -1:
bgY2 = bg.get_height()
event = pygame.event.poll()
if event.type == USEREVENT + 2:
#this makes it so the invincapple or milk is generated less than the dog
#this makes the game harder
r = random.randrange(0, 8)
if r == 0:
obstacles.append(invincapple(x[randomNo], 30, 50, 57))
elif (r >= 1 and r <= 6) or r == 8:
obstacles.append(dog(x[randomNo], 30, 70, 87))
elif r == 7:
obstacles.append(milk(x[randomNo], 30, 60, 100))
for obstacle in obstacles:
obstacleType = type(obstacle)
#this animates the obstacles
obstacle.y += 1.4
if obstacle.y < obstacle.height * -1:
obstacles.pop(obstacles.index(obstacle))
if ((cow.y - 1 < obstacle.y + obstacle.height)and (obstacle.y + obstacle.height < 450)
and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width)):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle,score, enteredUsername, mode, obstacleType)
keys = pygame.key.get_pressed()
#this is the keyboard control
if self.mode == "Standard":
if keys[pygame.K_LEFT]:
#this checks if cow is not already in left
if not(cow.left):
cow.left = True
cow.right = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the left position
if (cow.y - 1 < obstacle.y + obstacle.height)and (obstacle.y + obstacle.height <450) and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif keys[pygame.K_RIGHT]:
#this checks if cow is not already in right
if not(cow.right):
cow.right = True
cow.left = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the right position
if (cow.y - 1 < obstacle.y + obstacle.height) and (obstacle.y + obstacle.height <450) and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif keys[pygame.K_DOWN]:
#this places the cow back in the original centre position
cow.left = False
cow.right = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the centre position
if (cow.y - 1 < obstacle.y + obstacle.height) and (obstacle.y + obstacle.height < 450)and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif self.mode == "Hard":
if keys[pygame.K_s]:
#this checks if cow is not already in left
if not(cow.left):
cow.left = True
cow.right = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the left position
if (cow.y - 1 < obstacle.y + obstacle.height)and (obstacle.y + obstacle.height <450) and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif keys[pygame.K_h]:
#this checks if cow is not already in right
if not(cow.right):
cow.right = True
cow.left = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the right position
if (cow.y - 1 < obstacle.y + obstacle.height) and (obstacle.y + obstacle.height <450)and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif keys[pygame.K_c]:
#this places the cow back in the original centre position
cow.left = False
cow.right = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the centre position
if (cow.y - 1 < obstacle.y + obstacle.height) and (obstacle.y + obstacle.height < 450)and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif self.mode == "Beast":
if keys[pygame.K_a]:
#this checks if cow is not already in left
if not(cow.left):
cow.left = True
cow.right = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the left position
if (cow.y - 1 < obstacle.y + obstacle.height)and (obstacle.y + obstacle.height <450)and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif keys[pygame.K_k]:
#this checks if cow is not already in right
if not(cow.right):
cow.right = True
cow.left = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the right position
if (cow.y - 1 < obstacle.y + obstacle.height) and (obstacle.y + obstacle.height <450)and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
elif keys[pygame.K_v]:
#this places the cow back in the original centre position
cow.left = False
cow.right = False
for obstacle in obstacles:
obstacleType = type(obstacle)
#this checks if the cow is in collision when the cow is in the centre position
if (cow.y - 1 < obstacle.y + obstacle.height) and (obstacle.y + obstacle.height < 450)and (obstacle.x > cow.x and obstacle.x + obstacle.width < cow.x + cow.width):
cow.hit = True
obstacle.hit = True
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
else:
cow.hit = False
obstacle.hit = False
redrawGameWindow(obstacle, score, enteredUsername, mode, obstacleType)
if event.type == pygame.MOUSEMOTION:
mx, my = pygame.mouse.get_pos()
print("Mouse at (%d, %d)"%event.pos)
if (mx >= 560 and mx <= 590) and (my >= 10 and my <= 40):
pauseButton.color = lightOrange
pauseButton.redrawWindow(orange, blue, None)
pygame.display.update()
overPause = True
else:
pauseButton.color = orange
pauseButton.redrawWindow(orange, blue, None)
elif event.type == pygame.MOUSEBUTTONUP and overPause == True:
buttonSound = pygame.mixer.Sound('buttonClick.wav')
pygame.mixer.Sound.play(buttonSound)
time.sleep(0.3)
Game.pause(self, enteredUsername)
run = False
elif event.type == USEREVENT + 1:
speed += 1
else:
pygame.display.update()
crash = True
while crash:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crash = False
elif event.type == pygame.KEYDOWN:
#if event.key == pygame.K_ESCAPE:
crash = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
#this makes the function work
for b in buttonList:
if b.rect.collidepoint(pos):
b.call_back()
#draws all the buttons on a particular page
for b in buttonList:
b.draw(gameDisplay)
pygame.display.update()
gameFont = pygame.font.SysFont("Courier New", 20, bold = True)
#this sets what the title will say
global textSurface
textSurface = gameFont.render("Score: " + str(score) , False, black)
#puts the text on the window gameDisplay
gameDisplay.blit(textSurface, (0, 0))
clock.tick(speed)