Python Basic control flow errors - python

When I run this code, it enters a while loop and checks every turn whether or not on_title_screen==True. If it is true, the program will continue to check for input, but if it is false, the loop will refresh the screen and begin the game. However, when start is clicked, and on_title_screen=False, the game still captures mouse input, and does not display the bird that it should.
import random
import pygame
from pygame import *
import math
import sys
#Presets for window
size=width,height=500,500
Ag=-9.80665
clock = pygame.time.Clock()
white=(255,255,255)
blue=(0,0,255)
red=(255,0,0)
gray_bgColor=(190,193,212)
#Initialise pygame Surface as screen
pygame.init()
pygame.font.init()
screen=pygame.display.set_mode(size)
pygame.display.set_caption("Flappy Kid")
#Game Presets
vY=0
xPos,yPos=200,100
score=0
on_title_screen=True
def falling_loop():
for event in pygame.event.get():
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_UP:
vY=-10
if yPos>height-50:
yPos=100
vY+=1
yPos+=vY
class graphics():
#Holds the methods for loading/displaying graphics
def load_images(self):
#Loads the background and sprite images
self.background_image=pygame.image.load("flappy_background.png").convert()
self.bird_image=pygame.image.load("flappy_sprite.jpg").convert()
screen.set_colorkey(white)
self.birdHitBox=self.bird_image.get_rect()
def show_background(self):
#blits the background
screen.blit(self.background_image,[0,0])
def refresh_display(self):
#updates the display
screen.blit(self.background_image,[xPos,yPos],self.birdHitBox)
falling_loop()
screen.blit(self.bird_image,[xPos,yPos])
class titleScreen():
#Holds the methods for the title screen/menu
def title(self):
#Sets up the title
titleText="Flappy Game"
titlePos=(0,0)
currentFont=pygame.font.SysFont("arialms",30,bold=True,italic=True)
renderTitle=currentFont.render(titleText,1,blue,gray_bgColor)
self.titlex,self.titley=currentFont.size(titleText)
screen.blit(renderTitle,titlePos)
def start(self):
#Sets up the start Button
startText="Start Game"
self.startPos=(0,self.titley)
currentFont=pygame.font.SysFont("arialms",25,bold=False,italic=False)
renderStart=currentFont.render(startText,1,blue,gray_bgColor)
self.startx,self.starty=currentFont.size(startText)
self.start_rect = pygame.Rect(self.startPos[0],self.titley,self.startx,self.starty)
screen.blit(renderStart,self.startPos)
def quit(self):
#Sets up the quit button
quitText="Quit"
self.quitPos=(0,self.starty+self.titley)
currentFont=pygame.font.SysFont("arialms",25,bold=False,italic=False)
renderQuit=currentFont.render(quitText,1,red,gray_bgColor)
self.quitx,self.quity=currentFont.size(quitText)
self.quit_rect = pygame.Rect(self.quitPos[0],self.titley+self.starty,self.quitx,self.quity)
screen.blit(renderQuit,self.quitPos)
def get_click(self):
#Gets mouse click and processes outcomes
for event in pygame.event.get():
if event.type==pygame.MOUSEBUTTONDOWN:
x,y=pygame.mouse.get_pos()
#Tests for start:
if self.start_rect.collidepoint(x,y):
print("start")
on_title_screen=False
elif self.quit_rect.collidepoint(x,y):
print("quit")
sys.exit()
titleC=titleScreen()
graphicsC=graphics()
def setupTitle():
#bundles all title_screen functions
titleC.title()
titleC.start()
titleC.quit()
def main():
graphicsC.load_images()
graphicsC.show_background()
setupTitle()
while True:
clock.tick(30)
if on_title_screen==False:
graphicsC.refresh_display()
elif on_title_screen==True:
titleC.get_click()
pygame.display.flip()
main()

I think #TessellatingHeckler is right, on_title_screen is a shadow variable, not the same.
In this code, there is nowhere that on_title_screen (global) could ever be set to False.
A more powerful answer though is to explain how to find the problem. I strongly recommend using pdb or ipdb. In this case, I would put one just inside of the while loop and make sure that the variables are what I think they should be.

Related

Pygame: How do i make Fruits fall randomly without them getting struck on screen? [duplicate]

This question already has an answer here:
How can I move the ball instead of leaving a trail all over the screen in pygame?
(1 answer)
Closed 1 year ago.
Hey i am trying to make fruit catcher game in python using pygame but the fruits somehow get struck on screen(screenshot attached).The fruits and basket are getting screeched on the screen. I have also tried adding user defined events but then also the fruits images are getting screeched on the output screen. Can someone tell me what I am doing wrong?
import pygame
import time,random,sys
from pygame.locals import *
screenWidth=800
screenHeight=600
pygame.init()
screen=pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Fruit Catcher")
white=(255,255,255)
black=(0,0,0)
red=(255,0,0)
pygame.mixer.init()
clock=pygame.time.Clock()
font=pygame.font.SysFont("City Blueprint",50)
smallfont=pygame.font.SysFont("City Blueprint",20)
class Basket(pygame.sprite.Sprite):
def __init__(self):
super(Basket,self).__init__()
self.image=pygame.image.load("basket.png").convert_alpha()
self.image=pygame.transform.scale(self.image,(100,70))
self.rect=self.image.get_rect()
self.rect.x=0
self.rect.y=screenHeight-100
def update(self,pressed_keys):
if pressed_keys[K_LEFT]:
self.rect.move_ip(-5,0)
if pressed_keys[K_RIGHT]:
self.rect.move_ip(5,0)
if self.rect.left<0:
self.rect.left=0
if self.rect.right>screenWidth:
self.rect.right=screenWidth
class Fruits(pygame.sprite.Sprite):
def __init__(self,img):
super(Fruits,self).__init__()
self.image=pygame.image.load(img).convert_alpha()
self.image=pygame.transform.scale(self.image,(20,20))
self.rect=self.image.get_rect()
self.rect.x=random.randrange(screenWidth)
self.rect.y=0
self.speed=random.randint(1,7)
def update(self):
self.rect.y+=self.speed
if self.rect.bottom>screenHeight:
self.kill()
fruitsgroup=pygame.sprite.Group()
allsprites=pygame.sprite.Group()
fruits=["apple.png","guava.png","strawberry.png"]
def createBasket():
basket=Basket()
allsprites.add(basket)
return basket
def createFruits():
fruit=Fruits(random.choice(fruits))
fruitsgroup.add(fruit)
allsprites.add(fruit)
return fruit
def start():
screen.blit(pygame.image.load("background.jpg"),(0,0))
fruitsgroup.empty()
allsprites.empty()
basket=createBasket()
while True:
for event in pygame.event.get():
if event.type==QUIT:
return
pressedkeys=pygame.key.get_pressed()
basket.update(pressedkeys)
fruitsgroup.update()
if random.randrange(100)<2:
createFruits()
allsprites.draw(screen)
clock.tick(30)
pygame.display.update()
start()
pygame.quit()
You have to clear the display or draw the background in the application loop. Loading an image is a very time consuming operation. Load the background image once before the application loop, but blit it continuously in the loop:
def start():
# load and scale background
background = pygame.image.load("background.jpg"))
background = pygame.transform.scale(background, (screenWidth,screenHeight))
fruitsgroup.empty()
allsprites.empty()
basket=createBasket()
while True:
for event in pygame.event.get():
if event.type==QUIT:
return
pressedkeys=pygame.key.get_pressed()
basket.update(pressedkeys)
fruitsgroup.update()
if random.randrange(100)<2:
createFruits()
# clear screen / draw background
screen.blit(background, (0, 0))
allsprites.draw(screen)
pygame.display.update()
clock.tick(30)
The typical PyGame application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
Credit: https://stackoverflow.com/a/44686333/6660373
You need to add background before updating your fruits and basket.
add these two lines:
screen.fill((0,0,0))
screen.blit(pygame.image.load("background.jpg"),(0,0))
def start():
screen.blit(pygame.image.load("background.jpg"),(0,0))
fruitsgroup.empty()
allsprites.empty()
basket=createBasket()
while True:
for event in pygame.event.get():
if event.type==QUIT:
return
screen.fill((0,0,0)) # <--------------- here
screen.blit(pygame.image.load("background.jpg"),(0,0)) #<-----------here
pressedkeys=pygame.key.get_pressed()

Pygame_menu loop overrides the transition to another screen

Currently working on a backgammon game with eventual multiplayer support.
I have a mainmenu function that is working, and its exceptions and draws are handled by the mainloop() attribute. However, I have a button that, when pressed, should switch to the game with the backgammon board as the background.
The image appears briefly, then the main menu continues to run. I've tried to find ways to disable the menuloop using conditional statements to no avail.
Here is the full source code:
import sys, pygame, os, pygame_menu
width, height = 1280, 960
class mainBackgammonGame():
global width, height
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Bootleg Backgammon")
self.clock = pygame.time.Clock()
def updateScreen(self):
self.clock.tick(60)
pygame.display.flip()
def startGame():
surface = pygame.display.set_mode((width, height))
currPath = os.path.dirname(os.path.abspath(__file__))
boardPath = os.path.join(currPath, "images/mainboard.png")
boardImage = pygame.image.load(boardPath)
surface.blit(boardImage, (0,0))
pygame.display.flip()
def mainMenu():
surface = pygame.display.set_mode((width, height))
menu = pygame_menu.Menu(960, 1280, 'Welcome to Backgammon', theme = pygame_menu.themes.THEME_DARK)
menu.add_text_input("Your Name: ", default = "Joseph Smith")
menu.add_button('Play', mainBackgammonGame.startGame)
menu.add_button('Quit', pygame_menu.events.EXIT)
menu.mainloop(surface)
bg = mainBackgammonGame()
mainMenu()
while 1:
for event in pygame.event.get():
if event == pygame.QUIT:
exit()
bg.updateScreen()
Figured it out.
def mainMenu():
def disable():
menu.disable()
mainBackgammonGame.startGame()
surface = pygame.display.set_mode((width, height))
menu = pygame_menu.Menu(960, 1280, 'Welcome to Backgammon', theme = pygame_menu.themes.THEME_DARK)
menu.add_text_input("Your Name: ", default = "Joseph Smith")
menu.add_button('Play', disable)
menu.add_button('Quit', pygame_menu.events.EXIT)
menu.mainloop(surface)
Added a new function within the main menu function that initially disables the menu, then will call the startGame function that loads the screen.
I recommend reading the following example:
https://github.com/ppizarror/pygame-menu/blob/master/pygame_menu/examples/game_selector.py
You can see that the main part of that is having a main menu variable
main_menu: Optional['pygame_menu.Menu'] = None
Which gets initialized elsewhere in the code.
Additionally when it's time for that menu to leave, like if you want to move to the game after being in the menu then you want a function like this:
def start_game():
global menu
# Do stuff here
menu.disable()
Then in your pygame main loop you can guard the mainloop call like so:
if menu.is_enabled():
menu.mainloop(screen)

How to integrate 'MENU' code for my game with the actual gaming code?

I have created a basic game. Now I want to expand on the basic game and add a video game menu to it. I have two programs:
Basic game code
MENU code
I want to integrate both codes into one so that my game becomes more functional. I am just a beginner and need directions on how to do that. Thanks for helping.
BASIC GAME CODE:
import pygame
import random
import sys
pygame.init()
w=800
h=600
red=(251,63,75)
blue=(104,41,171)
yellow=(255,255,0)
player_size=25
player_pos=[w/2,h-(2*player_size)]
enemy_size=25
enemy_pos=[random.randint(0,w-enemy_size),0]
enemy_list=[ ]
bg_color=(0,0,0)
screen=pygame.display.set_mode((w,h))
game_over=False
speed=10
score=0
clock=pygame.time.Clock()
myFont=pygame.font.SysFont("monospace",35)
def set_level(score,speed):
if score<10:
speed=5
elif score<20:
speed=6
elif score<30:
speed=8
elif score<40:
speed=10
elif score<50:
speed=13
elif score<200:
speed=15
else:
speed=20
return speed
def drop_enemies(enemy_list):
delay=random.random()
if len(enemy_list)<6 and delay<0.1:
x_pos=random.randint(0,w-enemy_size)
y_pos=0
enemy_list.append([x_pos,y_pos])
def draw_enemies(enemy_list):
for enemy_pos in enemy_list:
pygame.draw.rect(screen,blue,
(enemy_pos[0],enemy_pos[1],enemy_size,enemy_size))
def update_enemy_pos(enemy_list,score):
for idx,enemy_pos in enumerate(enemy_list):
if enemy_pos[1]>=0 and enemy_pos[1]<h:
enemy_pos[1]+=speed
else:
enemy_list.pop(idx)
score+=1
return score
def detect_collision(player_pos,enemy_pos):
p_x=player_pos[0]
p_y=player_pos[1]
e_x=enemy_pos[0]
e_y=enemy_pos[1]
if (e_x>=p_x and e_x<(p_x+player_size)) or (p_x>=e_x and p_x<(e_x+enemy_size)):
if (e_y>=p_y and e_y<(p_y+player_size)) or (p_y>=e_y and p_y<(e_y+enemy_size)):
return True
return False
def collision_check(enemy_list,player_pos):
for enemy_pos in enemy_list:
if detect_collision(enemy_pos,player_pos):
return True
return False
while not game_over:
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
if event.type==pygame.KEYDOWN:
x=player_pos[0]
y=player_pos[1]
if event.key==pygame.K_LEFT:
x-=player_size
elif event.key==pygame.K_UP:
y-=player_size
elif event.key==pygame.K_RIGHT:
x+=player_size
elif event.key==pygame.K_DOWN:
y+=player_size
player_pos=[x,y]
screen.fill(bg_color)
drop_enemies(enemy_list)
score=update_enemy_pos(enemy_list,score)
speed=set_level(score,speed)
text='Your Score is:' + str(score)
label=myFont.render(text,1,yellow)
screen.blit(label,(w/2,h-40))
if collision_check(enemy_list,player_pos):
game_over=True
break
draw_enemies(enemy_list)
pygame.draw.rect(screen,red,
(player_pos[0],player_pos[1],player_size,player_size))
clock.tick(30)
pygame.display.update()
pygame.display.flip()
GAME MENU CODE:
import pygame
import random
import sys
pygame.init()
w=800
h=600
bg_color=(34,139,34)
red=(255,0,0)
blue=(0,0,125)
bright_blue=(0,0,255)
font_size=35
b1_pos=[w/2-50,h/2]
b1_size=[105,50]
screen=pygame.display.set_mode((w,h))
myFont=pygame.font.SysFont("freesansbold.tff",font_size)
def button(b1_pos,b1_size):
mouse_pos=pygame.mouse.get_pos()
click=pygame.mouse.get_pressed()
if (b1_pos[0]<mouse_pos[0]<(b1_pos[0]+b1_size[0])) and (b1_pos[1]<mouse_pos[1]<(b1_pos[1]+b1_size[1])):
pygame.draw.rect(screen,bright_blue,(b1_pos[0],b1_pos[1],b1_size[0],b1_size[1]))
if click[0]==1:
print("Left click")
else:
pygame.draw.rect(screen,blue,(b1_pos[0],b1_pos[1],b1_size[0],b1_size[1]))
text='START'
label=myFont.render(text,1,red)
screen.blit(label,(w/2-38,h/2+5))
game_over=False
while not game_over:
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
screen.fill(bg_color)
button(b1_pos,b1_size)
pygame.display.update()
When creating a game you need something called The MainLoop. All the code that needs to be updated in every frame goes inside this loop. This loop runs forever until the game is terminated. Check these video tutorials and this
Let me give you an example:
import pygame
#Import literals such as QUIT
from pygame.locals import *
pygame.init()
w = 800
h = 600
screen = pygame.display.set_mode((w,h))
running = True
def MenuCode():
pass
def GameCode():
pass
#This is the Game Loop.
while running:
#Events are used to check if a key has
#been pressed or a mouse button or a mouse movement.
for event in pygame.event.get():
#If the user pressed the x button.
#terminate the while loop.
if event.type == QUIT:
running = False
break;
#In every frame you must clean the window with a color
#in order to draw anythin else above it.
screen.fill((0,0,0))
#Here draw anything you like
#Also somewhere here call all the code that needs to be
#called every frame (Menu code, Game code, etc)
MenuCode()
GameCode()
#Lastly you must update the display.
#The most important thing that this does
#is called buffer swapping, check it out.
pygame.display.update()
#When the loop terminates, terminate pygame.
pygame.quit()
If you want to learn what the update() method does check about double buffering

Pygame Menu: calling another .py file

I'm learning pygame by helping a friend make a Menu for his interactive TicTacToe game. It's simple enough, a title and 2 buttons for starting and exiting the game. He has the game done, I just need to link my menu to his game.
After fiddling with pygame, I finally finished making the images appear in the pygame window(I never thought that seeing text appear in a blank window for the first time could look so beautiful! T^T). I believe that the next step is to make the images act like buttons to call another python file.
Here is my simple code for the menu:
import pygame
from pygame.locals import *
from sys import exit
pygame.init()
resX, resY = 640, 480
windowObj = pygame.display.set_mode((resX,resY))
titleImg = pygame.image.load("title.png")
startImg = pygame.image.load("start.png")
exitImg = pygame.image.load("exit.png")
def width_center(img):
"""For horizontally setting an image."""
return resX/2 - x(img)/2
def height_center(img):
"""For vertically setting an image."""
return resY/2 - y(img)/2
def x(img):
"""Width of object."""
return img.get_width()
def y(img):
"""Height of object."""
return img.get_height()
while True:
pygame.display.update()
windowObj.fill((255,255,255))
windowObj.blit(titleImg,(width_center(titleImg), 30))
#This I want to link:
windowObj.blit(startImg,(width_center(startImg),height_center(startImg)-10))
windowObj.blit(exitImg,(width_center(exitImg),height_center(exitImg)+y(startImg)))
for i in pygame.event.get():
if i.type == QUIT:
exit()
Simply put, I want to know how to make the startImg call TTTClick.py. Should there also be a certain format for his TTTClick.py?
Thanks :)
If it's one project, you can have 'title screen' state, and 'game' states.
Psuedo code:
class Game():
def __init__(self):
self.done = False
self.state = "title"
def game_draw(self):
# game draw
def game_update(self):
# game event handling, and physics
def title_draw(self):
# title draw
def title_update(self):
# on event click
self.state = "game"
def loop(self):
# main loop
while not self.done:
if state == 'title':
title_update()
title_draw()
elif state == 'game':
game_update()
game_draw()
if __name__ == "__main__":
game = Game()
game.loop()
Note: x, height_center ect. already exist in pygame.Rect
# if Surface
titleImage.get_rect().width
# if Sprite
titleImage.rect.width
There's more, rect.center, rect.centerx, see the full listing at http://www.pygame.org/docs/ref/rect.html

USB controller will not work in Pygame

I have a USB controller that I have mapped to be the arrow keys on the keyboard, outside of gaming programs (as in, you can use it as the normal arrow keys on the keyboard). I did this using the program ControlMK. My Pygame program will not recognize the controller as the keyboard. When I try to use the Joystick modules, the program does not function properly.
Here is my code:
import pygame, sys, time, random
from pygame.locals import *
# set up pygame
try:
pygame.init()
pygame.display.init()
pygame.mixer.init(size=8, buffer=2048)
pygame.mixer.get_init
except:
print "error in init\n"
white=(255,255,255)
screen=pygame.display.set_mode((800,600), pygame.RESIZABLE)
class Loadsound:
def __init__(self, name, key, sound_file):
self.name = name
self.name=key
self.sound = pygame.mixer.Sound(sound_file)
sound_left=[]
sound_left.append(Loadsound("left","K_LEFT", "left.wav"))
sound_right=[]
sound_right.append(Loadsound("right","K_RIGHT", "right.wav"))
sound_up=[]
sound_up.append(Loadsound("up","K_UP","up.wav"))
sound_down=[]
sound_down.append(Loadsound("down","K_DOWN","down.wav"))
while True:
for i in pygame.event.get():
if i.type==QUIT:
exit()
pressed=pygame.key.get_pressed()
if pressed[K_LEFT]:
for left in sound_left:
left.sound.play()
elif pressed[K_RIGHT]:
for right in sound_right:
right.sound.play()
elif pressed[K_UP]:
for up in sound_up:
up.sound.play()
elif pressed[K_DOWN]:
for down in sound_down:
down.sound.play()
Thank you for the help!
Edit:
I have been trying to use the Joystick module. Here is where I was taking example code from:
http://www.pygame.org/wiki/Joystick_analyzer
I edited my code to include some of it, but it still does not work. Here is my edited code:
import pygame, sys, time, random
from pygame.locals import *
from pygame import *
# set up pygame
try:
pygame.init()
pygame.display.init()
pygame.mixer.init(size=8, buffer=2048)
pygame.mixer.get_init
except:
print "error in init\n"
white=(255,255,255)
screen=pygame.display.set_mode((800,600), pygame.RESIZABLE)
class Loadsound:
def __init__(self, name, key, sound_file):
self.name = name
self.name=key
self.sound = pygame.mixer.Sound(sound_file)
sound_left=[]
sound_left.append(Loadsound("left","K_LEFT", "left.wav"))
sound_right=[]
sound_right.append(Loadsound("right","K_RIGHT", "right.wav"))
sound_up=[]
sound_up.append(Loadsound("up","K_UP","up.wav"))
sound_down=[]
sound_down.append(Loadsound("down","K_DOWN","down.wav"))
def __init__(self):
pygame.joystick.init()
self.my_joystick = None
self.joystick_names = []
for i in range(0, pygame.joystick.get_count()):
self.joystick_names.append(pygame.joystick.Joystick(i).get_name())
print self.joystick_names
if (len(self.joystick_names) > 0):
self.my_joystick = pygame.joystick.Joystick(0)
self.my_joystick.init()
#max_joy = max(self.my_joystick.get_numaxes(), self.my_joystick.get_numbuttons(), self.my_joystick.get_numhats()
while True:
for i in pygame.event.get():
pygame.event.pump()
if i.type==QUIT:
exit()
#pygame.joystick.Joystick(0)
#Joystick.init()
pressed=pygame.key.get_pressed()
#pressed_j=Joystick.get_hat()
def check_hat(self, p_hat):
if (self.my_joystick):
if (p_hat,self.my_joystick.get_numhats()):
return self.my_joystick.get_hat(p_hat)
return (0, 0)
if check_hat==(-1,0):
#if pressed[K_LEFT]:
for left in sound_left:
left.sound.play()
elif pressed[K_RIGHT]:
for right in sound_right:
right.sound.play()
elif pressed[K_UP]:
for up in sound_up:
up.sound.play()
elif pressed[K_DOWN]:
for down in sound_down:
down.sound.play()
For clarity, my code DOES work when using the keyboard. However, it does not translate to the controller which is mapped to the same keys.
You'll need to use Pygame's Joystick module, or something similar, which has method's such as: Joystick.get_init(), which tells if the joystick is initialized in Pygame, and Joystick.get_axis(axis_number) which returns the Joystick's position, as a float, along a given axis axis_number. ControlMK is likely mapping the joystick to key inputs at too high of a level to interact with Pygame, though there may be some way to change that, its documentation seems limited.
Try this:
import pygame
pygame.init()
print "Joystics: ", pygame.joystick.get_count()
my_joystick = pygame.joystick.Joystick(0)
my_joystick.init()
clock = pygame.time.Clock()
while 1:
for event in pygame.event.get():
print my_joystick.get_axis(0), my_joystick.get_axis(1)
clock.tick(40)
pygame.quit ()

Categories