I can't get python to work when I am using my Raycast function to display images, how do I fix this?
I tried moving some variables and played around with the function, but I can't seem to get it to work.
import pygame
pygame.init()
Screen = "Title"
DB = 0
Width = 800
Height = 600
Frame = pygame.display.set_mode((Width,Height))
pygame.display.set_caption("GAME")
FPS = pygame.time.Clock()
def Raycast(RayXPos, RayYPos):
RaycastThis = pygame.image.load(TTR)
Frame.blit(RaycastThis, (RayXPos, RayYPos))
Loop = True
while Loop == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
pygame.display.update()
FPS.tick(60)
while Screen == "Title" and DB == 0:
TTR = 'TitleScreenSmall.png'
Raycast(0, 0)
I expected the frame to display the image (the same size as the window) and it instead crashed, and I can't run the program
Your problem is the infinite loop:
while Screen == "Title" and DB == 0:
TTR = 'TitleScreenSmall.png'
Raycast(0, 0)
Since the loop control variables Screen and DB never change, you have no way to exit the loop. You're stuck here, eternally repeating a function that does very little, and includes no changes to observe.
See this lovely debug blog for help.
Related
import pygame
import time
# WINDOW SETUP
window = pygame.display.set_mode((900, 500))
pygame.display.set_caption("Pong")
time.sleep(5)
FPS = 60
# RGB VALUE VARIABLES
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
def background(window):
window.fill(WHITE)
pygame.display.update()
# FRAMERATE AND EVENT LOOP INITIALIZATION
def main():
run = True
clock = pygame.time.Clock()
while run:
clock.tick(FPS)
background(window)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if running == False:
pygame.quit()
Above, is my code. I'm trying to make a pong game with pygame. The text editor I am coding with is Visual Studios Code (VSCODE).
Firstly, you need to call the main. You should also make you're code nice and easy to read when possible. I imported pygame as pg which makes typing pygame functions a bit faster as you have less to type. Also, it's better to use global variables to hold variables that won't change through the program, like screen width, height, colours, etc. Then make sure you initialise the module.
As well as that, the only update you have is in background(). You should put the update at the bottom of the loop and remove it from background(). This way everything above will update each loop.
I apologise for not adding you're FPS counter in here as well but I think this should be enough to help you get you're window running with more readable code and a more efficient loop.
import pygame as pg
# Global Variables
screen_width = 900
screen_height = 500
screen = pg.display
window = screen.set_mode((screen_width, screen_height))
colour = 'red'
def main():
# Initialise module
pg.init()
pg.display.set_caption('PONG')
running = True
while running:
# This is a better way of writing your loop
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
# Call background function
background()
# Updates window
# place this inside the loop near the bottom
# so everything is updated at the end of each loop
screen.flip()
def background():
window.fill(colour)
# Remember to call your main function
# This if statement is good practise but not required
# You can just place main() here
if __name__ == '__main__':
main()
I’m trying to use pyttsx3 in a game where speech is said in response to events within the game, however I can’t figure out how to execute speech commands without pausing the game loop until the audio finishes. Using runAndWait() is no good for this reason, and I can’t get the example in the docs using iterate() to work as I need it to either. See the code below:
import pyttsx3
import pygame as pg
def onStart(name):
print('start')
def onWord(name, location, length):
print('word', name, location, length)
def onEnd(name, completed):
print('end')
def speak(*args, **kwargs):
engine.connect('started-utterance', onStart)
engine.connect('started-word', onWord)
engine.connect('finished-utterance', onEnd)
engine.say(*args, **kwargs)
def main():
engine.startLoop(False)
n = 0
while True:
n += 1
print(n)
if n == 3:
speak('The first utterance.')
elif n == 6:
speak('Another utterance.')
engine.iterate()
clock.tick(1)
if __name__ == '__main__':
pg.init()
engine = pyttsx3.init()
clock = pg.time.Clock()
main()
pg.quit()
sys.exit()
In this example, the first statement is triggered at the right time, but it seems like pyttsx3 stops processing at that point - no further say commands produce any sound, and only the first started-utterance event fires - the started-word and finished-utterance commands never fire. I’ve tried this every way I can think of and still can’t get it to work. Any ideas?
I'm not familiar with pyttx3, but I've created an example that incorporates a pygame event loop. The colour changes with every mouse click event and the name of the colour is spoken.
import random
import pygame
import pyttsx3
WIDTH = 640
HEIGHT = 480
FPS = 120
simple_colors = [
"red",
"orange",
"yellow",
"green",
"blue",
"violet",
"purple",
"black",
"white",
"brown",
]
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# TTS Setup
engine = pyttsx3.init()
engine.startLoop(False) # have to call iterate in the main loop
# set a random color
current_color = random.choice(simple_colors)
# create a centered rectangle to fill with color
color_rect = pygame.Rect(10, 10, WIDTH - 20, HEIGHT - 20)
frames = 0
paused = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONUP:
current_color = random.choice(simple_colors)
engine.stop() # interrupt current speech?
engine.say(f"The next color is {current_color}")
# update game elements
pygame.display.set_caption(
f"Color: {current_color:10} Frame: {frames:10} FPS: {clock.get_fps():.1f}"
)
# draw surface - fill background
window.fill(pygame.color.Color("grey"))
## draw image
window.fill(pygame.color.Color(current_color), color_rect)
# show surface
pygame.display.update()
# call TTS Engine
engine.iterate()
# limit frames
clock.tick(FPS)
frames += 1
pygame.quit()
engine.endLoop()
If you run this you'll see a repetition of the problem you described, the game loop pausing, indicated by the frame count in the title bar. I used a longer sentence rather than just the colour name to exacerbate the issue. Perhaps someone with a better understanding of pyttx3 will understand where we've both gone wrong. In any case we can get around this by running the Text to Speech engine in a different thread.
import random
import threading
import queue
import pygame
import pyttsx3
# Thread for Text to Speech Engine
class TTSThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
self.daemon = True
self.start()
def run(self):
tts_engine = pyttsx3.init()
tts_engine.startLoop(False)
t_running = True
while t_running:
if self.queue.empty():
tts_engine.iterate()
else:
data = self.queue.get()
if data == "exit":
t_running = False
else:
tts_engine.say(data)
tts_engine.endLoop()
WIDTH = 640
HEIGHT = 480
FPS = 120
simple_colors = [
"red",
"orange",
"yellow",
"green",
"blue",
"violet",
"purple",
"black",
"white",
"brown",
]
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# create a queue to send commands from the main thread
q = queue.Queue()
tts_thread = TTSThread(q) # note: thread is auto-starting
# set a random color
current_color = random.choice(simple_colors)
# Initial voice message
q.put(f"The first color is {current_color}")
# create a centered rectangle to fill with color
color_rect = pygame.Rect(10, 10, WIDTH - 20, HEIGHT - 20)
frames = 0
paused = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
q.put("exit")
elif event.type == pygame.MOUSEBUTTONUP:
current_color = random.choice(simple_colors)
q.put(f"The next color is {current_color}")
# update game elements
pygame.display.set_caption(
f"Color: {current_color:10} Frame: {frames:10} FPS: {clock.get_fps():.1f}"
)
# draw surface - fill background
window.fill(pygame.color.Color("grey"))
## draw image
window.fill(pygame.color.Color(current_color), color_rect)
# show surface
pygame.display.update()
# limit frames
clock.tick(FPS)
frames += 1
pygame.quit()
In this case, we're using a queue to send the text to the thread which will perform the text-to-speech, so the frame counter does not pause. Unfortunately we can't interrupt the speech, but that might not be a problem for your application.
Let me know if you need any further explanation of what's going on, I've tried to keep it simple.
EDIT: Looking at this issue recorded on github it seems that speech interruption on Windows is not working, the work-around in that discussion is to run the text-to-speech engine in a separate process which is terminated. I think that might incur an unacceptable start-up cost for process and engine re-initialisation every time an interruption is desired. It may work for your usage.
So i wrote this code:
# Pygame development 4
# Focus on making code object oriented
# Introduce classes and objects into our code
# Gain access to the pygame library
import pygame
# Size of the screen
SCREEN_TITLE = 'Crossy RPG'
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
# Colors according to RGB codes
WHITE_COLOR = (255, 255, 255)
BLACK_COLOR = (0, 0 , 0)
# Clock used to update game events and frames
clock = pygame.time.Clock()
pygame.font.init()
font = pygame.font.SysFont('comicsans', 75)
class Game:
# Typical rate of 60, equivalent to fps
TICK_RATE = 60
# Initializer for the game class to set up the width, height, and title
def __init__(self, title, width, height):
self.title = title
self.width = width
self.height = height
# Create the window of specified size in white to display the game
self.game_screen = pygame.display.set_mode((width, height))
# Set the game window color to white
self.game_screen.fill(WHITE_COLOR)
pygame.display.set_caption(title)
def run_game_loop(self):
is_game_over = False
# Main game loop, used to update all gameplay suh as movement, check, and graphics
# Runs unit is_game_over = True
while not is_game_over:
# A loop to get a;l of the events occuring at any given time
# Events are most often mouse movement, mouse and button clicks, or eit events
for event in pygame.event.get():
# If we have a quite type event(exit out) then exit out of the game loop
if event.type == pygame.QUIT:
is_game_over = True
print(event)
# Update all game graphics
pygame.display.update()
# Tick the clock to update everything within the game
clock.tick(self.TICK_RATE)
pygame.init()
new_game = Game(SCREEN_TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
new_game.run_game_loop()
pygame.quit()
quit()
Right now I am learning to code with python so im following a course online and since I couldn't get help from the forums of that website I thought I might ask the question here! So I've looked at the code multiple times to check for spelling mistakes but I couldn't find any and anyway i think that it's' not about something missing but it has something to do with pygame.display.update ! Can somebody pls help me?
Without running your code or having a stack trace of where the problem happens, we need to debug the code for you first. So it would be beneficial to add a full stack trace to your questions. I'm pretty confident however that there's two issues that you should work out.
pygame.display.update() should be correctly indented to be in the while loop of your main game event loop. Secondly, the pygame.init() should be run before any other initialization (or at least so I've been taught over the years and every example points to)
Try this out, I think it solves your problem:
# Pygame development 4
# Focus on making code object oriented
# Introduce classes and objects into our code
# Gain access to the pygame library
import pygame
pygame.init()
# Size of the screen
SCREEN_TITLE = 'Crossy RPG'
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
# Colors according to RGB codes
WHITE_COLOR = (255, 255, 255)
BLACK_COLOR = (0, 0 , 0)
# Clock used to update game events and frames
clock = pygame.time.Clock()
pygame.font.init()
font = pygame.font.SysFont('comicsans', 75)
class Game:
# Typical rate of 60, equivalent to fps
TICK_RATE = 60
# Initializer for the game class to set up the width, height, and title
def __init__(self, title, width, height):
self.title = title
self.width = width
self.height = height
# Create the window of specified size in white to display the game
self.game_screen = pygame.display.set_mode((width, height))
# Set the game window color to white
self.game_screen.fill(WHITE_COLOR)
pygame.display.set_caption(title)
def run_game_loop(self):
is_game_over = False
# Main game loop, used to update all gameplay suh as movement, check, and graphics
# Runs unit is_game_over = True
while not is_game_over:
# A loop to get a;l of the events occuring at any given time
# Events are most often mouse movement, mouse and button clicks, or eit events
for event in pygame.event.get():
# If we have a quite type event(exit out) then exit out of the game loop
if event.type == pygame.QUIT:
is_game_over = True
print(event)
# Update all game graphics
pygame.display.update()
# Tick the clock to update everything within the game
clock.tick(self.TICK_RATE)
new_game = Game(SCREEN_TITLE, SCREEN_WIDTH, SCREEN_HEIGHT)
new_game.run_game_loop()
pygame.quit()
This also seams to be a school assignment and not a online course (but I might be wrong here), never the less I'll leave this piece of advice if I'm right. I strongly suggest that if you bump into problems, ask your teacher for guidance. As there's always a reason for teachers giving you a challenge/problem to solve. It teaches you the latest techniques you've learned in class, and if you can't solve the problem with the tools that you've been given - you've most likely haven't learned the fundamentals that has been taught out - and you should really re-do some steps.
I just wrote some code that works in the commandline, so now I'd like to give it some graphics. Now, this is my very first programming project so bear with me as I try to explain the problem:
I'm using PyGame and initialised the window as follows:
import pygame, pygame.midi,pygame.font, random
(width, height) = (600, 400)
background = (220,220,220)
pygame.midi.init()
pygame.font.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Chord trainer")
screen.fill(background)
pygame.display.flip()
Then I attempt to render text (which does not give any errors):
myfont = pygame.font.SysFont("Arial", 80)
letter = myfont.render("SOME WEIRD TEST TO TRY AND GET THINGS WORKING",0,(0,0,0))
screen.blit(letter,(100,100))
And because I'd like to actually see my text before the program closes, I set up an infinite loop:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
When I run it, I just get the grey screen I wanted, but without any sort of text, which would make me think that there's something wrong with my blit command, but I can't figure out what.
Initially I had the rendering set in a loop, but that just made the program unresponsive so I took is out for debugging. For completeness, here is that loop:
while True:
# Decide on random chord
c1 = random.choice(chords)
# Make sure that no repitition takes place.
if c1==c2:
while c1==c2:
c1=random.choice(chords)
c2 = c1
myfont = pygame.font.SysFont("Arial", 80)
letter = myfont.render(str(c1),0,(0,0,0))
screen.blit(letter,(100,100))
# Listen to Midi device and search for c.
midi_listen(inp,sorted(c1))
score += 1
You need to add
pygame.display.flip()
after
letter = myfont.render("SOME WEIRD TEST TO TRY AND GET THINGS WORKING",0,(0,0,0))
screen.blit(letter,(100,100)
It will update your screen and normally you will be able to see your text.
I have created some sort of menu navigation system in my game. All the screens are blitted in. The "Play" and "Quit" and "Controls" button works just fine but when I try to press menu from the controls screen, nothing happens. On the controls screen, you can faintly see the first menu screen from before. That might be the problem. I think that as the return to menu button is over the previous controls page button, it somehow is pressing the controls button from before. The button and menu segment of my code will be pasted here and the full thing will be pasted in a pastebin.
def text_to_button(msg,color,buttonx,buttony,buttonwidth,buttonheight,size = "small"):
textSurf, textRect = text_objects(msg,color,size)
textRect.center = ((buttonx + buttonwidth/2)), buttony+(buttonheight/2)
gameDisplay.blit(textSurf, textRect)
def button(text,x,y,width,height,inactive_color,active_color,size = "small",action = None):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
#print(click)
if x + width > cur[0] > x and y + height > cur[1] > y:
pygame.draw.rect(gameDisplay, active_color,(x,y,width,height))
if click[0] == 1 and action != None:
if action == "quit":
pygame.quit()
quit()
if action == "controls":
game_controls()
if action == "play":
gameLoop()
if action == "main":
game_intro()
else:
pygame.draw.rect(gameDisplay, inactive_color,(x,y,width,height))
text_to_button(text,black,x,y,width,height,size)
def game_controls():
gcont = True
while gcont:
gameDisplay.blit(cont,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("Main Menu",320,500,150,50,white,gray,"tiny", action = "main")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
def game_intro():
intro = True
while intro:
gameDisplay.blit(imggg,(0,0))
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("ControLs",320,500,150,50,white,gray,"tiny", action = "controls")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
intro = False
Full Code: https://pastebin.com/jrd82gkJ
You will have very hard time to debug your code in order to achieve the behavior you want for one simple reason:
The logic you use to switch between different screens providing different functionality is causing much trouble you can't directly see if you only run the game.
So you think: "oh ... how come the button doesn't work, there must be an issue with the button".
You are probably not aware of the fact that using functions having own while loops you go deeper and deeper into recursive calls with increasing recursion depth with each switch from one view to another - it is not how pygame is thought to be programmed.
I suggest you add some print() commands into your code to see in the console output that the code doesn't really do what you expect even if it appears to be OK at the first glance because it works.
Then I suggest you REWRITE your entire code so that you have one main while notGameExit: loop, and don't use any other looping in the helper functions. If you want use looping in your helper functions at least don't call from the helper functions another functions with own loops (and so on), but RETURN from them with an explicit return to avoid recursion.
If you leave the in the main loop called function with return your main loop will continue running and depending on some switches you can display in it different things on the screen and react differently to user actions.
Maybe looking at a minimal working pygame script showing "action" without usage of a loop you will gain better understanding and some deep "enlightenment" about how pygame works and then start a total rewrite of your game using another approach as this one you have used in the current code? Then come back with what you have achieved if you have further questions, but you won't probably have any, because it would be much easier to debug it yourself if the code will become more straightforward.
import pygame
pygame.init() # start PyGame (necessary because 'import pygame' doesn't start PyGame)
winDisplay = pygame.display.set_mode((1024, 768)) # set PyGame window size to 1024x768 pixel
pygame.display.set_caption("Minimal PyGame Test Script")
# Time in pygame is measured in milliseconds (1/1000 seconds) (defined by TIMER_RESOLUTION constant):
pygame.TIMER_RESOLUTION = 1000 # assure 1000 explicit, don't relay on default value
colorWhite = (255, 255, 255) # RGB color in Pygame format (valueRed=255, valueGreen=255, valueBlue=255)
colorRed = (255, 0, 0)
colorGreen = ( 0, 255, 0)
colorBlue = ( 0, 0, 255)
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorRed)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorGreen)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorBlue)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds