Reputation: 155
I have created 2 screens and a button to allow you to play again should you either get caught by the monster or win. However, despite the button (on both screens) showing and changing colour when the mouse is hovering over it, the click/link isn't working properly. When on the 'caught' screen, if I click the button several times it will eventually return to the game but at the exact point where you were caught by the monster, rather than go back to the beginning as I intended. And when on the win screen, the click/link isn't working at all. I copied the code from another game where it works fine, you click the button and the game restarts, thus I'm really not sure what the issue it. I'm including all of the code as I think it might help. Thank you in advance!
import pygame
import random
import os
os.environ['SDL_VIDEO_CENTERED'] = '1'
#Initalise pygame
pygame.init()
#Colours required
black = (0,0,0)
blue = (0,0,255)
green = (0,200,0)
red = (255,0,0)
orange = (255,200,0)
bright_green = (0,255,0)
#Set up the display
width = 640
height = 480
screen = pygame.display.set_mode((width, height))
background = pygame.image.load('path.png')
caption = pygame.display.set_caption('Escape from the mazes!')
clock = pygame.time.Clock()
#Class for the player rect
class Player(object):
def __init__(self, pos):
self.rect = pygame.Rect(pos[0], pos[1], 32, 32) #x-axis, y-axis, width, height
self.image = pygame.image.load('player.png')
def move(self, dx, dy):
#Move each axis separately. NB this checks for collisions both times
if dx != 0:
self.move_single_axis(dx, 0)
if dy != 0:
self.move_single_axis(0, dy)
def move_single_axis(self, dx, dy):
#Move the rect
self.rect.x += dx
self.rect.y += dy
#If you collide with a wall, move out based on velocity
for wall in walls:
if self.rect.colliderect(wall.rect):
if dx > 0: #Moving right, hit the left side of wall
self.rect.right = wall.rect.left
if dx < 0: #Moving left, hit the right side of wall
self.rect.left = wall.rect.right
if dy > 0: #Moving down, hit the top side of wall
self.rect.bottom = wall.rect.top
if dy < 0: #Moving up, hit the bottom side of wall
self.rect.top = wall.rect.bottom
#Class for the monster rect
class Monster(object):
def __init__(self, pos):
self.rect = pygame.Rect(pos[0], pos[1], 32, 32)
self.image = pygame.image.load('monster.png')
self.dist = 3
self.direction = random.randint(0, 3)
self.steps = random.randint(3, 9) * 32
def move(self):
direction_list = ((-1,0), (1,0), (0,-1), (0,1))
dx, dy = direction_list[self.direction]
self.rect.x += dx
self.rect.y += dy
collide = False
for wall in walls:
if self.rect.colliderect(wall.rect):
collide = True
if dx > 0:
self.rect.right = wall.rect.left
if dx < 0:
self.rect.left = wall.rect.right
if dy > 0:
self.rect.bottom = wall.rect.top
if dy < 0:
self.rect.top = wall.rect.bottom
self.steps -= 1
if collide or self.steps == 0:
#New random direction
self.direction = random.randint(0, 3)
self.steps = random.randint(3, 9) * 32
#Class for the wall rect
class Wall(object):
def __init__(self, pos):
self.rect = pygame.Rect(pos[0], pos[1], 32, 32)
self.image = pygame.image.load('hedge.png')
#Class for end rect
class Finish(object):
def __init__(self, pos):
self.rect = pygame.Rect(pos[0], pos[1], 32, 32)
self.image = pygame.image.load('gate.png')
#Variables
currentLevel = 0
#Holds the level layout in a list of strings
levels = [[
'WWWWWWWWWWWWWWWWWWWW',
'WP W W',
'W WWWWWW W',
'W WWWW W W',
'W W WWWW W',
'W WWW WWWW W',
'W W MW W W',
'W W W WWW WW',
'W WWW WWW W W W',
'W W W W W W',
'WWW W WWWWW W W',
'W W WW W',
'W W WWWW WWWWWWW',
'W W FW',
'WWWWWWWWWWWWWWWWWWWW',
],
[
'WWWWWWWWWWWWWWWWWWWW',
'W W W W FW',
'W W W W W',
'W W W W W W WWW',
'W W W W W W W',
'W W W W W W W',
'W W W W W W W W',
'W W M W W W W',
'W W W W WWW',
'WWW WWWWWWW W W',
'W W W W',
'W W WWWWWWW W',
'WWWWW W W',
'WP W W',
'WWWWWWWWWWWWWWWWWWWW',
],
[
'WWWWWWWWWWWWWWWWWWWW',
'WP W W W',
'W W WWWW WWWW W W',
'W W W W W',
'W WWWW W WWWW W',
'W W W WW W',
'W W W W WWWWW',
'WWWW W W MW FW',
'W W W W WWWWWWWW',
'W W W W',
'W W W W',
'W W WWWWWWWWWWW W',
'W W W',
'W W W',
'WWWWWWWWWWWWWWWWWWWW',
],
[
'WWWWWWWWWWWWWWWWWWWW',
'W W W',
'W W M W',
'W W W WWWWWWWW W',
'W W W W W',
'W W W W W',
'W W W W WWWWWWWW',
'WP W W W W',
'WWWW W W W',
'W W WWWWWWWW W',
'W W W W',
'W WWWW W W',
'W W WWWWWWWW',
'W W FW',
'WWWWWWWWWWWWWWWWWWWW',
],
[
'WWWWWWWWWWWWWWWWWWWW',
'W W W FW',
'W W WWW W W',
'W W WWWW W WWWW',
'W W W W W',
'W WWWW WWWW W W W',
'W MW W WWWW W',
'W W W W',
'W W WWWW WWWWWWWW',
'W W W W',
'W W W W',
'WWWW W WWWWWWWW W',
'W W W',
'WP W W',
'WWWWWWWWWWWWWWWWWWWW',
],
[
'WWWWWWWWWWWWWWWWWWWW',
'WP W W W W',
'WWWWW W W W W W',
'W W W WWWWWWW W W',
'W W W M W W',
'WW W W W WWWWW W',
'W W W W W WWW',
'W WWWWW WWWWW W WFW',
'W W W W W',
'WWWWWW W WWWWWWW W W',
'W W W W W',
'W W WWW W W W',
'W W W WWWWWWW W',
'W W W W',
'WWWWWWWWWWWWWWWWWWWW',
]]
def load_level(level):
walls = []
players = []
monsters = []
finishes = []
#Parse the level string above. W = wall, F = exit, P = player, M = monster
x = y = 0
for row in levels[level]:
for col in row:
if col == 'W':
walls.append(Wall((x, y)))
if col == 'P':
players.append(Player((x, y)))
if col == 'M':
monsters.append(Monster((x, y)))
if col == 'F':
finishes.append(Finish((x, y)))
x += 32
y += 32
x = 0
return walls, players, monsters, finishes
walls, players, monsters, finishes = load_level(currentLevel)
Highest_level = len(levels)-1 #index of last level
def button(msg,x,y,w,h,ic,ac,action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(screen, ac, (x,y,w,h))
if click[0] == 1 and action != None:
action()
else:
pygame.draw.rect(screen, ic, (x,y,w,h))
smallText = pygame.font.Font("freesansbold.ttf", 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x+(w/2)), (y+(h/2)))
screen.blit(textSurf, textRect)
def text_objects(text, font):
textSurface = font.render(text, True, black)
return textSurface, textSurface.get_rect()
def win():
screen.fill(blue)
largeText = pygame.font.Font('freesansbold.ttf', 90)
TextSurf, TextRect = text_objects('You Escaped!', largeText)
TextRect.center = (int((width/2)), int((height/2)))
screen.blit(TextSurf, TextRect)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button('Play Again',280,350,110,50,green,bright_green,main)
pygame.display.update()
clock.tick(15)
def caught():
screen.fill(red)
largeText = pygame.font.Font('freesansbold.ttf', 75)
TextSurf, TextRect = text_objects('You Got Caught!', largeText)
TextRect.center = (int((width/2)), int((height/2)))
screen.blit(TextSurf, TextRect)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button('Try Again',280,350,100,50,green,bright_green,main)
pygame.display.update()
clock.tick(15)
def main():
global walls, players, monsters, currentLevel, finishes
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
pygame.quit()
quit()
#Move the player if an arrow key is pressed
key = pygame.key.get_pressed()
if key[pygame.K_LEFT]:
player.move(-2, 0)
if key[pygame.K_RIGHT]:
player.move(2, 0)
if key[pygame.K_UP]:
player.move(0, -2)
if key[pygame.K_DOWN]:
player.move(0, 2)
#Move monster
for monster in monsters:
monster.move()
#Moving to next level/win
for player in players:
for finish in finishes:
if player.rect.colliderect(finish.rect):
if currentLevel < Highest_level:
currentLevel +=1
walls, players, monsters, finishes = load_level(currentLevel)
else:
win()
#Getting caught by the monster
for player in players:
for monster in monsters:
if player.rect.colliderect(monster.rect):
caught()
#Draw the scene
screen.fill(blue)
screen.blit(background, (0,0))
for wall in walls:
#pygame.draw.rect(screen, green, wall.rect)
screen.blit(wall.image, wall.rect)
for player in players:
#pygame.draw.rect(screen, orange, player.rect)
screen.blit(player.image, player.rect)
for monster in monsters:
#pygame.draw.rect(screen, bright_green, monster.rect)
screen.blit(monster.image, monster.rect)
for finish in finishes:
#pygame.draw.rect(screen, red, finish.rect)
screen.blit(finish.image, finish.rect)
pygame.display.update()
main()
pygame.quit()
quit()
Upvotes: 2
Views: 66
Reputation: 211277
Sorry, but that does not work like that. The action of the button can not be the main application loop (function main
).
What you actually do is to execute the main application loop. If the player is caught, then the function caught
is called.
In caught
is another loop, which is executed endless. If the button is pressed, then the main
is called.
At this point you've the following situation:
main
|
+--caught
|
+--main
Since the game state has not changed, the player is caught immediately in the inner (main
) application loop and caught
is called again:
main
|
+--caught
|
+--main
|
+-caught
That continues infinitely.
I'll show you haw to fix this for caught
.
Create an function, which resets the current game state. The function resets the current level to its begin:
def load_current_level():
global walls, players, monsters, finishes
walls, players, monsters, finishes = load_level(currentLevel)
Change the function button
in that way, that it returns True
when the button was clicked and else False
:
def button(msg,x,y,w,h,ic,ac,action=None):
clicked = False
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(screen, ac, (x,y,w,h))
if click[0] == 1 and action != None:
action()
clicked = True
else:
pygame.draw.rect(screen, ic, (x,y,w,h))
smallText = pygame.font.Font("freesansbold.ttf", 20)
textSurf, textRect = text_objects(msg, smallText)
textRect.center = ((x+(w/2)), (y+(h/2)))
screen.blit(textSurf, textRect)
return clicked
Terminate the loop in caught
, when the button was pressed. The action which is associated to the button is load_current_level
:
def caught():
screen.fill(red)
largeText = pygame.font.Font('freesansbold.ttf', 75)
TextSurf, TextRect = text_objects('You Got Caught!', largeText)
TextRect.center = (int((width/2)), int((height/2)))
screen.blit(TextSurf, TextRect)
try_again = False
while not try_again:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
try_again = button('Try Again',280,350,100,50,green,bright_green,load_current_level)
pygame.display.update()
clock.tick(15)
When the button is pressed, then the level is reset and the loop in caught
is terminated. caught
returns to the main application loop and you can retry the level.
Do something similar in win
:
def load_first_level():
global walls, players, monsters, finishes, currentLevel
currentLevel = 0
walls, players, monsters, finishes = load_level(currentLevel)
def win():
screen.fill(blue)
largeText = pygame.font.Font('freesansbold.ttf', 90)
TextSurf, TextRect = text_objects('You Escaped!', largeText)
TextRect.center = (int((width/2)), int((height/2)))
screen.blit(TextSurf, TextRect)
play_again = False
while not play_again:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
play_again = button('Play Again',280,350,110,50,green,bright_green,load_first_level)
pygame.display.update()
clock.tick(15)
Upvotes: 1