How to switch between multiple while statements in Python - python

I am working on a program and i need to switch through different loops.
this works thought when i try to switch back to the previous loop i crashes.
Any suggestions?
P.S. the bellow are examples
e.g. Function = Home
(change loop)
Function = txtbox
(change loop)
Function = Home (Crashes here)
import pygame, sys, time, random
from pygame.locals import *
import math
import sys
import os
# set up pygame
pygame.init()
# set up the window
WINDOWWIDTH = 1200
WINDOWHEIGHT = 650
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 1, 32)
pygame.display.set_caption("Mango")
Function = "Home"
font = pygame.font.SysFont("Fonts", 30)
#colors
TEXTCOLOR = (255, 255, 255)
TEXTCOLORS = (255, 0, 0)
# run the game loop
while Function == "Home":
# check for the QUIT event
events = pygame.event.get()
for event in events:
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
Function = "txtbox"
break
pygame.display.flip()
while Function == "txtbox":
events = pygame.event.get()
# process other events
for event in events:
if event.type == pygame.MOUSEBUTTONUP:
Function = "Home"
break
pygame.display.flip()

It doesn't crash. It simply finishes execution when Function is set to "Home" in the last loop. That loop simply ends.
Try enclosing those two while loops inside another while loop that runs forever.
while True:
while Function == "Home":
# check for the QUIT event
events = pygame.event.get()
for event in events:
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
Function = "txtbox"
break
pygame.display.flip()
while Function == "txtbox":
events = pygame.event.get()
# process other events
for event in events:
if event.type == pygame.MOUSEBUTTONUP:
Function = "Home"
break
pygame.display.flip()

You're on a good track.
Try this:
extract every state of your game to a function,
have a variable that knows which state is currently "active".
Example code:
def home():
events = pygame.event.get()
for event in events:
...
if something_happened:
switch_state(txtbox)
def txtbox():
events = pygame.event.get()
for event in events:
...
if something:
switch_state(home)
Function = home # assign the function itself to a variable
def switch_state(new_state):
global Function
Function = new_state
...
while True:
Function() # call the function which is currently active
Next steps:
Write the states as objects, instead of functions (so that they can keep some data about themselves - for example you'd have a state "Level" and all data about the particular level in it)
Instead of one global Function(), keep a list of states, so that you can push a new state on top, and then pop it and go back to whatever state you've been on previously. This will let you manage multiple game screens easily.

Related

How do I stop the screen from updating?

I'm making a calculator in pygame but when I click the button, I want the number to stay on the screen but instead of staying on the screen, the number just appears when my mouse is clicked. When I release it, the numbers disappears. Does anyone know a solution for this?
My code:
import pygame
from sys import exit
pygame.init()
screen = pygame.display.set_mode((600,800))
pygame.display.set_caption("Calculator")
clock = pygame.time.Clock()
font1 = pygame.font.Font("c:/Users/oreni/OneDrive/Masaüstü/sprites/minecraft.ttf", 100)
one = 1
one_main = font1.render(str(one), False, "black")
one_main_r = one_main.get_rect(center = (75,100))
one_button = pygame.Surface((142.5,142.5))
one_button.fill("white")
one_button_r = one_button.get_rect(topleft = (0,160))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill("black")
screen.blit(one_button,one_button_r)
if event.type == pygame.MOUSEBUTTONDOWN:
if one_button_r.collidepoint(event.pos):
screen.blit(one_main,one_main_r)
pygame.display.update()
clock.tick(60)
The usual way is to redraw the scene in each frame. You need to draw the text in the application loop. Set a variable that indicates that the image should be drawn when the mouse is clicked, and draw the image according to that variable:
draw_r = False
run = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if one_button_r.collidepoint(event.pos):
draw_r = True
screen.fill("black")
screen.blit(one_button,one_button_r)
if draw_r:
screen.blit(one_main, one_main_r)
pygame.display.update()
clock.tick(60)
pygame.quit()
exit()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()

How to remove an image from memory in pygame without using SpriteGroups?

I am trying to remove an image from memory to increase the efficiency of my code without the use of SpriteGroups as I am unfamiliar with that concept.
import pygame
import sys
pygame.init()
#constants
LENGTH = 454
SCREEN = pygame.display.set_mode((LENGTH, LENGTH))
def show(img, x, y):
image = pygame.image.load(img)
SCREEN.blit(image, (x, y))
def home():
show('image1.png', 10, 10)
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_SPACE:
#code to remove the image
pass
def main():
while True:
SCREEN.fill((0, 0, 0))
home()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
main()
Here is a simple minimal code to keep the problem as general as possible all this code does is to remove the image on pressing space.
Earlier I tried approaching it by either taking it outside the screen,
or just rendering other objects over it.
However the image isn't deleted completely I want to remove it not only from play but also from memory.
From past few days the 'www.pygame.org' site has been in solidarity hence unable to refer to the documentation
There are multiple problems in your code.
pygame.event.get() get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get() is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed. Get the events once per frame and use them in multiple loops or pass the list of events to functions and methods where they are handled (see Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?).
Do not load the image in each frame. pygame.image.load is a very expensive operations. It has to load the image from the volume and interpret the image data. Load the image once at initialization.
Removing an image just means not to draw the image. Set image = None and only draw the image if image != None. Use the global statement to change a variable in gloabl namespace within a function:
import pygame
import sys
pygame.init()
#constants
LENGTH = 454
SCREEN = pygame.display.set_mode((LENGTH, LENGTH))
image = pygame.image.load('image1.png')
def show(img, x, y):
SCREEN.blit(img, (x, y))
def home(event_list):
global image
for event in event_list:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
image = None
if image:
show(image, 10, 10)
def main():
run = True
while run:
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
run = False
SCREEN.fill((0, 0, 0))
home(event_list)
pygame.display.update()
pygame.quit()
sys.exit()
main()

Pygame event inside class not recognized

I have completed a game using pygame without any problems. Now I am trying to organise the code and add classes. However, I am having a problem with the event command.
I tried using pygame.event.poll() and pygame.event.get(), but neither helped.
class MainRun():
run = True
def Main(self):
#some code
while MainRun.run:
pygame.time.delay(35)
for event in pygame.event.get():
if event.type == pygame.QUIT:
MainRun.run = False
a.activate_skills()
class Player():
#code
def activate_skills(self):
if event.type == pygame.MOUSEBUTTONDOWN:
#some code
a = Player
main = MainRun().Main()
if event.type == pygame.MOUSEBUTTONDOWN: NameError: name 'event' is not defined
So how can I define the event? Please see what I have already tried.
You should only call pygame.event.get() once, as it will fetch all the events that have happened. For example:
a = pygame.event.get() # Contains the events that has happen.
for event in a:
if event.type == pygame.QUIT:
quit()
b = pygame.event.get() # Will probably contain nothing, as the code above took the events from the event queue.
for event in b:
if event.type == pygame.MOUSEBUTTONDOWN:
do_something()
do_some_calculation()
c = pygame.event.get() # Might contain something, if the user did something during the time it took to do the calculation.
for event in c:
if event.type == pygame.MOUSEBUTTONDOWN:
do_other_thing()
In the above example, it's likely do_something() will never be called, as the event queue has been cleared just before. do_other_thing() might be called, but that's only if the user pressed the button during the time it took to execute do_some_calculations(). If the user pressed before or after, the click event will have been cleared and lost.
So in your situation, you could do something like this:
class MainRun():
run = True
def Main(self):
#some code
while MainRun.run:
pygame.time.delay(35)
for event in pygame.event.get(): # ONLY CALLED HERE IN THE ENTIRE PROGRAM.
if event.type == pygame.QUIT:
MainRun.run = False
a.activate_skills(event) # MOVED THIS INTO THE FOR LOOP!
class Player():
#code
def activate_skills(self, event): # TAKING THE EVENT AS PARAMETER.
if event.type == pygame.MOUSEBUTTONDOWN:
#some code
a = Player
main = MainRun().Main()
Try this, hope it works for you :D
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
# your code

Pygame Window Not Responding

I am trying to make a game in Pygame where he objective is to start the game but the start button keeps moving whenever you touch it but the window will not respond. I am not finished with the code yet because I tested it and it didn't work. Here is my code so far:
import pygame
import random
import time
pygame.init()
display = pygame.display.set_mode((800,600))
pygame.display.set_caption('BEST 3D PLATFORMER FPS GAME!')
clock = pygame.time.Clock()
pygame.display.update()
clock.tick(60)
display.fill((255,255,255))
def newposition()
randx = random.randrange(100, 700)
randy = random.randrange(100,500)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pass
if event.ty
button = pygame.image.load('start.png')
display.blit(button,(randx,randy))
pygame.quit()
quit()
All comments inside code
import pygame
import random
# --- constants --- (UPPER_CASE names)
WHITE = (255, 255, 255) # space after every `,`
FPS = 30
# --- classes --- (CamelCase names)
#empty
# --- functions --- (lower_case names)
def new_position():
x = random.randrange(100, 700) # space after every `,`
y = random.randrange(100, 500) # space after every `,`
return x, y # you have to return value
# --- main --- (lower_case names)
# - init -
pygame.init()
display = pygame.display.set_mode((800, 600)) # space after every `,`
pygame.display.set_caption('BEST 3D PLATFORMER FPS GAME!')
# - objects -
# load only once - don't waste time to load million times in loop
button = pygame.image.load('start.png').convert_alpha()
button_rect = button.get_rect() # button size and position
button_rect.topleft = new_position() # set start position
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
#pass # it does nothing so you can't exit
running = False # to exit `while running:`
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False # to exit `while running:`
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # left button
button_rect.topleft = new_position() # set new position
# if event.ty # Syntax Error
# - updates (without draws) -
#empty
# - draws (without updates) -
# you have to use it inside loop
display.fill(WHITE) # clear screeen before you draw elements in new place
display.blit(button, button_rect)
# you have to use it inside loop
pygame.display.update() # you have to send buffer to monitor
# - FPS -
# you have to use it inside loop
clock.tick(FPS)
# - end -
pygame.quit()
BTW: simple template which you can use when you start new project.
PEP 8 -- Style Guide for Python Code
I had a similar issue, the fix is not straight forward. Here are my notes for python 3.6.1 and Pygame 1.9.3:
1) The event is unresponsive because there is no display generated for pygame, add a window display after pygame initialization:
pygame.init() # Initializes pygame
pygame.display.set_mode((500, 500)) # <- add this line. It generates a window of 500 width and 500 height
2) pygame.event.get() is a generates a list of event but not all event classes have .key method for example mouse motion. Thus, change all .key event handling codes such as
if event.key == pygame.K_q:
stop = True
To
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
stop = True
3) In some mac/python combinations even after the window is generated it doesn't focus / record keyboard events, this is a pygame issue and is fixed in a reimplementation of pygame using sdl2 (SDL is a cross-platform development library which provides low level access to keyboard, audio ,mouse etc). it can be installed by following the instructions here https://github.com/renpy/pygame_sdl2. One might need to install homebrew for it, which is another package manager for macOS. Instructions can be found here https://brew.sh/
4) after installing it using the instructions on github link you need to change all import pygame to import pygame_sdl2 as pygame
5) Voila! fixed ...
You've got to load button outside the loop (it only needs to be done once.)
button = pygame.image.load('start.png')
Also, you have defined newposition(), but have not called it. Also, randx and randy would not be accessible from outside of the function, because the would be local to it.
So, change your function to this :
def newposition()
randx = random.randrange(100, 700)
randy = random.randrange(100,500)
return randx, randy # Output the generated values
Then, before the loop :
rand_coords = newposition()
You simply forgot to update the pygame display with your modifications to it.
At the end of your loop, add pygame.display.update(), like this:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pass
# if event.ty why is that here?
display.blit(button,(rand_coords[0],rand_coords[1])) # Take our generated values
pygame.display.update()
Final code :
import pygame
import random
import time
pygame.init()
display = pygame.display.set_mode((800,600))
pygame.display.set_caption('BEST 3D PLATFORMER FPS GAME!') # Yeah, exactly :)
clock = pygame.time.Clock()
display.fill((255,255,255))
def newposition()
randx = random.randrange(100, 700)
randy = random.randrange(100,500)
return randx, randy # Output the generated values
rand_coords = newposition() # Get rand coords
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # Quit pygame if window in closed
# if event.ty why is that here?
clock.tick(60) # This needs to be in the loop
display.fill((255,255,255)) # You need to refill the screen with white every frame.
display.blit(button,(rand_coords[0],rand_coords[1])) # Take our generated values
pygame.display.update()

Change a value using mouse click with pygame

I am trying to create a nice and simple game just for practice with pygame, and I was trying to change a value using mouse click and I can't find out what to do
global item
ev = pygame.event.get()
item = 0
while True:
for event in ev:
if event.type == QUIT:
pygame.quit()
sys.exit()
for event in ev:
if event.type == pygame.MOUSEBUTTONDOWN:
item + 1
print (item)
After this is run, and I click the mouse, the game just freezes and nothing appears in the shell.
Please help
Thanks
Welcome to stackoverflow.
A simple script where clicking in the window increments item by 1 and prints it:
import pygame
pygame.init()
screen = pygame.display.set_mode((400,400))
clock = pygame.time.Clock()
item = 0
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
item += 1
print item
clock.tick(30)
pygame.quit()
This example shows the basic layout and flow of a pygame program.
Notice the for event in pygame.event.get() loop contains both of the loops in your example.
Hope this helps

Categories