I am having a hard time understanding the window.timeout() function. To be more specific, I am toying with a "snake" game in python:
s = curses.initscr()
curses.curs_set(0)
w = curses.newwin()
w.timeout(100)
while True:
move snake until it hits the wall
I understand that in this case, timeout(100) determines how fast the snake "moves", i.e. printing out new characters on the screen. However, I got stuck when I want to amend the code so that it waits until someone press "start". I wrote something like:
w.timeout(100)
while True:
if w.getch() is not start:
stay at the initial screen
else:
while True:
move the snake until it hits the wall
However, in this case, the timeout(100) seems to govern how long each time the program waits for w.getch(), not how long to wait between each time the snake moves. Also, I notice that in the first example, the timeout is declared at the top, outside the while loop. This looks weird to me because normally if I want to pause a while loop, I would put sleep() at the bottom inside the while loop.
If you want to pause between snake moves, you could use napms to wait a given number of milliseconds (and unlike sleep, does not interfere with screen updates). Setting w.timeout to 100 (milliseconds) is probably too long. If you're not concerned with reading function-keys, you could use nodelay to set the w.getch to non-blocking, relying on the napms to slow down the loop.
Regarding the followup comment: in ncurses, the wtimeout function sets a property of the window named _delay, which acts within the getch function, ultimately passed to a timed-wait function that would return early if there's data to be read.
Related
I have this pygame code that goes a little like this (obviously not my actual code since its a little long):
def draw():
win.fill(color)
<code for drawing stuff>
pygame.display.update()
def stuff():
while doingStuff:
<some lines of code>
draw()
win = pygame.display.set_mode((width,height))
while True:
<some lines of code>
if conditionMet:
stuff()
draw()
The problem is that when the "stuff" function runs, the pygame window freezes and doesnt update until it leaves the function. The draw function is correct I think, as it runs fine as long as it isn't in the function.
How do I make the pygame window keep updating whilst the function runs?
You may have to use threading or multiprocessing, because it is essential that you understand why your main render function is 'freezing'.
This means while your main method always renders everything so fast in a loop, that you don't see how long the draw() methods needs to calculate the new scene, it becomes obvious how long the stuff() or condition method needs to evaluate a result. Your main loop for drawing freezes because the calculation of the inner while loop from stuff() takes so long to complete. This is my assumption.
This happens because you program sequential. To solve this you need to put the stuff() function into its own program space - or better process space which is usually done with threads, which are subprocesses of your main process.
On the other hand you could try to speed up your stuff() method.
This is the programme I wrote but I'm not sure what's wrong:-
import turtle
import random
bob = turtle.Turtle()
screen = turtle.Screen()
def coord(x,y):
print(x,y)
turtle.onscreenclick(None)
turtle.onscreenclick(coord)
turtle.listen()
print('hello')
turtle.done()
The programme works fine except that the print('hello') part happens first, followed by the on screen event. How do I make the onscreen event occur first before the rest of my programme?
You can simply make the rest of your code part of the coord function:
def coord():
print(x,y)
turtle.onscreenclick(None)
print("Hello")
# The rest of your program goes here.
However, a few things to note:
This isn't an amazing elegant solution, especially if you intend to set up other events further into your code. It can become quite hard to keep track of.
It's imperative that you remove the event binding (in this case the binding of coord to onscreenclick) as soon as it's been used, otherwise you could end up with multiple instances of the same code running at once if someone double-clicked the screen, for example. In your case you've already done this (with turtle.onscreenclick(None)), but it is something to keep in mind.
If you choose to go this route, don't forget to rename the coord function something more representative of what that section of your code will do.
How do you make the code stop for a moment before checking for something else? (I'm new to code)
if BonusTime==True and Drop==True:
if event.type == pygame.MOUSEBUTTONDOWN:
window.blit(Fired,(mouseX-12,mouseY-12))
Cankill=True
#I want it to delay here
Cankill=False
There is a cross hair that follows the mouse and when I click it, it fires. The problem is, you can just hold the mouse down and leave the cross hair in one place. Whenever an enemy walks into the cross hair, they die. I need it so even when you hold it will only fire once. I plan to make it delay the if statement, to set "Cankill" to true and then wait a second, after waiting, it should set "Cankill" to false. I've already looked through a lot of other people's questions similar to this and haven't found something I can understand. So if you could please help me find out how to delay it in the way I need.
"Pausing" is not what you want - if you do that, your game will just freeze, and nothing will move (since you are usign the OS mouse pointer, maybe it could move).
Anyway, the function to "pause" inside a game is pygame.time.wait(1000) - the number is in miliseconds.
Waht you actually need is to mark down the time the click was made, continue with the game, and when 1 second has passed, reset the variable back to the other state.
Something along:
last_trigger = 0
while True:
# game updating code goes here (getting events, and such)
...
if Cankill and pygame.time.get_ticks() - last_trigger > 1000:
Cankill = False
if event.type == pygame.MOUSEBUTTONDOWN:
window.blit(Fired,(mouseX-12,mouseY-12))
Cankill=True
last_trigger = pygame.time.get_ticks()
The "get_ticks" call returns the number of miliseconds that passed since pygame was initialized - and is usefull for this time of timers.
I wrote a modified program of the 'mines' game, and I hope it shows every step/click graphically. I use time.sleep(0.5) to make a pause. So, in general the main program is like:
check_block():
if mine == 0:
buttons[current].config(image = tile_clicked)
elif mine == 1:
buttons[current].config(image = tile[1])
...
while(1):
time.sleep(0.5)
check_block()
get_next()
if check_fail():
break
However, the buttons don't update every 0.5 second: they are all updated together when the game(loop) finishes.
I guess it's just like 'cout' in C++: if you don't flush they will get stacked. So, is there a method to get them updated step by step, or say, instantly?
Thanks!
In all GUI systems you have to allow the message loop to run so that Windowing events occur promptly. So do not use a while loop like this. Instead, create a method that calls check_block() and get_next() and use after to call that function after a delay. At the end of that function, you use after again to call the same function again so that this function is called every 0.5 second forever. The after function queues a timer event and then lets the message queue be processed. Once your timer event fires, the callback function is run which allows you to do things and keep the UI responsive.
You should never call sleep in a GUI program. This is because the GUI must be "awake" at all times so that it can service events (including internal events that cause the screen to update). Instead, leverage the already-running eventloop by using the after method to put events on the queue at regular intervals.
In your case, you would replace the while loop with something like:
def do_check():
check_block()
if not check_fail():
root.after(500, do_check)
# in your initialization code, start the loop by calling it directly:
do_check()
I don't know what your get_next function does, so I don't know if you need to call it periodically too. Probably not. I'm guessing it waits for the next button press, which you don't need to do with tkinter or most other GUI toolkits. Instead, you configure the button to call a function when clicked.
Regardless, the way to do the type of looping you want is to place events on the event queue at a regular interval.
I am new to programming with Python. I have been working through a tutorial book that I found, and got the game up and running, but then decided I wanted to have a "Play Again?" option at the end. I can get the game to quit out with a press of the "n" key, but cannot work out how to get the game to restart.
Here is the code I think is giving the trouble:
#player reaches treasure
if player_rectangle.colliderect(treasure_rectangle):
#display text
screen.blit(text,(screen_width/2-195,screen_height/2-25))
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_n:
exit()
elif event.key==pygame.K_y:
pygame.display.update()
I know something needs to go after the elif event, and I have tried all that I can think of. I tried to define the whole program, and call it but that stopped the whole thing running. I have looked around internet sites, but just cannot seem to come up with a answer.
Can some one help out in easy terms how to get the game to restart to the starting position when the y key is pressed? I know it has something to do with a loop, I just cannot place my finger on what.
Many thanks.
It's not entirely clear how your code is organized, so I'll be very general. Usually games are implemented with a "main loop" that handles all of the action. In "pseudo"-python:
def main_loop():
while True:
handle_next_action()
draw_screen()
if game_is_over():
break
Before you start the loop, you usually do some setup to get the game state how you want it:
def main():
setup()
main_loop()
shut_down()
Given those parts, you can reset the game by having the main loop code call setup again (it may need to be specifically designed to be runable more than once):
def main_loop():
while True:
handle_events()
draw_screen()
if game_is_over():
if play_again(): # new code here!
setup()
else:
break
You might want to split the setup code into two parts, one which only needs to be run when the program begins (to read configuration files and set up things like the window system), and a second that gets repeated for each new game (setting up the game's state).
To restart a game you normally need to reset all variables to their initial value (e.g. number of lives, score, initial position, ...).
The best way is to put all initialisations inside a procedure:
def init():
global score,lives # use these global variables
score=0
lives=3
init() # call init() to define and reset all values
while 1: # main loop
...
elif event.key==pygame.K_y:
init() # restart the game