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.
Related
I'm making a Tetris game now. I want to implement it so that if I press the down key , the block falls quickly, and if I press the left and right keys, the block moves quickly. Pressing the key used the pygame.key.get_pressed() function and used pygame.time.set_timer() function to make speed change. The game speed was set to 600 for the interval of pygame.time.set_timer(), but if I press the down key, the block drops quickly because the interval was set to 150 to speed up the game so that the block drops quickly. The problem is to implement the function on the left and right direction keys. It is also possible to move the left and right keys quickly if I change the interval. The problem is that the pygame.time.set_timer() function changes the speed of the entire game, so the block falls quickly as well as the left and right movements of the block. Is there a way to speed up left and right movements without touching the speed of other things? I'd appreciate it if you let me know, thanks!
code
elif start:
for event in pygame.event.get():
attack_stack = 0
pos = pygame.mouse.get_pos()
if event.type == QUIT:
done = True
elif event.type == USEREVENT:
# Set speed
if not game_over:
keys_pressed = pygame.key.get_pressed()
# Soft drop
if keys_pressed[K_DOWN]:
pygame.time.set_timer(pygame.USEREVENT, 100)
elif keys_pressed[K_RIGHT]:
pygame.time.set_timer(pygame.USEREVENT, 100)
if not is_rightedge1(dx, dy, mino_en, rotation, matrix):
ui_variables.move_sound.play()
dx += 1
elif keys_pressed[K_LEFT]:
pygame.time.set_timer(pygame.USEREVENT, 100)
if not is_leftedge1(dx, dy, mino_en, rotation, matrix):
ui_variables.move_sound.play()
dx -= 1
else:
pygame.time.set_timer(pygame.USEREVENT, 600)
Waiting a long time (100 ms is already long) before reacting to user input feels bad, so you don’t want to wait a full piece-movement time before checking for input again just because there is none at the moment you check. Instead, poll for input at a steady pace of (say) 30 Hz; for simplicity, the usual approach is to just run the whole game at that frequency even if nothing needs to change on the screen for some (or even most) frames. (This technique also naturally allows smooth animations of or between piece movements.)
The usual implementation of “nothing” on a frame is to adjust the piece’s position every frame but integer-divide that position by some constant before using it for anything other than keeping track of its progress toward the next movement (like drawing it or checking for collisions). You might use pixels as the “invisible unit” when movement must be by whole tiles; games where sprites can be drawn at any pixel divide each into some convenient number of subpixels in the same fashion.
It looks to me that the reason your piece is dropping faster when you press a button is because if the user doesn't press a button the timer is set to 600ms. If they do press a button then the timer is set to 100ms.
As for how to fix this, you'll need to decouple the downward piece movement and user-input movement. I'd suggest making another event that only handles downward movement.
DROPEVENT = pygame.USEREVENT + 1
elif event.Type == DROPEVENT:
pygame.time.set_timer(DROPEVENT, 600)
# Your piece drop logic.
This snippet is not complete nor tested at all, but I hope it get the idea across. You don't seem to have posted the logic that handles dropping the piece, but you would need to move this into the new event.
So right now, i have a platformer and i want to make it so when i click on a button, the whole game restarts.
In main.py:
level=Level(level_map,screen)
while running:
if game_state=='game_active':
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
pygame.font.quit()
sys.exit()
level.run()
screen.blit(sky_surface,(0,0))
pygame.display.update()
clock.tick(60)
in level.py:
class Level:
def __init__(self,level_data,surface):
self.display_surface=surface
self.level_building(level_data)
def level_building(self,tilesheet):
self.coins=pygame.sprite.Group()
self.player=pygame.sprite.GroupSingle()
for row_index,row in enumerate(level_map):
for col_index,cell in enumerate(row):
self.x=col_index*tile_size
self.y=row_index*tile_size
if cell=='R':
self.coin_sprite=Recyclables((self.x+22,self.y+55))
self.coins.add(self.coin_sprite)
if cell=='P':
self.player_sprite=Player((self.x+10,self.y))
self.player.add(self.player_sprite)
def collisions(self):
playercoin=pygame.sprite.groupcollide(self.coins,self.player,True,False) # kills the coin (to show it has been picked up)
if len(playercoin)==1:
self.score+=1
def run(self):
self.coins.draw(self.display_surface)
self.collisions()
self.player.draw(self.display_surface)
After my game finishes running, what is a good way to restart everything, and respawn all the sprites that were killed? (did not show the kill code since it'd be too long) so far i've tried killing all sprites after the game but i don't know how to re-draw everything.
In PyGame, you're in full control of what's being drawn on the screen every frame, so I'm not sure why you wouldn't be sure how to redraw things.
Since you apparently have already encapsulated your game logic into the Level class, restarting the level shouldn't require more than just
level = Level(level_map, screen)
so subsequent calls to level.run() use a fresh level.
(Also, unless you're doing esoteric things that you're not showing us here, you shouldn't necessarily need to even "kill sprites".)
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.
I want to have a delay between firing bullets for my character. I used to do this before in Java like:
if (System.currentTimeMillis() - lastFire < 500) {
return;
}
lastFire = System.currentTimeMillis();
bullets.add(...);
However, how can I do this in pygame way, in order to get that sys currentTimeMillis.This is how my run (game loop) method looks like:
time_passed = 0
while not done:
# Process events (keystrokes, mouse clicks, etc)
done = game.process_events()
# Update object positions check for collisions...
game.update()
# Render the current frame
game.render(screen)
# Pause for the next frame
clock.tick(30)
# time passed since game started
time_passed += clock.get_time()
As you can see in the previous code, I have created time passed, but I'm not sure if that is correct way of code order, and what else im missing.
Your code is fine, if game.process_events and game.update works as expected.
Edit:
Use pygame.time.get_ticks instead of the clock I mentioned earlier. It was using python's time module, so that clock and clock in your code meant different clocks. This is much better way.
#this should be done only once in your code *anywhere* before while loop starts
newtime=pygame.time.get_ticks()
# when you fire, inside while loop
# should be ideally inside update method
oldtime=newtime
newtime=pygame.time.get_ticks()
if newtime-oldtime<500: #in milliseconds
fire()
Let me explain you what pygame.time.get_ticks() returns:
On first call, it returns time since pygame.init()
On all later calls, it returns time (in milliseconds) from the first call to get_ticks.
So, we store the oldtime and substract it from newtime to get time diff.
Or, even simpler, you can use pygame.time.set_timer
Before your loop:
firing_event = pygame.USEREVENT + 1
pygame.time.set_timer(firing_event, 500)
Then, an event of type firing_event will be posted onto the queue every 500 milliseconds. You can use this event to signal when to fire.
This question already has answers here:
How to efficiently hold a key in Pygame?
(7 answers)
Closed 8 years ago.
I am trying to write a Pong game in which I can move the paddle using the up and down arrows. I created a Paddle object that updates by a given amount (passed as the parameter "num" in the code below) each time the up key is pressed. What I want to do is allow the user to hold the up button down which would cause the paddle to continuously move in the up direction. I tried writing this event handling in a while loop, but I got stuck in an infinite loop. Here is the code below:
for event in PE.get():
if event.type == PG.KEYDOWN:
keystate = PG.key.get_pressed()
if event.key == PG.K_ESCAPE:
done = True
while keystate[PL.K_UP]:
rightPaddle.update(-20)
if event.type == PG.QUIT:
done = True
Below is the code for the Paddle object:
class Paddle(object):
def __init__(self, x, y):
self.topleftx = x
self.toplefty = y
self.width = 15
self.height = 100
def draw(self, surface):
rect = PR.Rect(self.topleftx, self.toplefty, \
self.width, self.height)
surface.fill(WHITE, rect)
def update(self, num):
self.toplefty += num
I checked other stackoverflow questions on this topic, which is how I found the PG.key.getPressed() method, but other answers suggest using "sprites" which I'm not sure how to use. Could anyone offer some advice on how to go about performing this task?
The problem with the while loop is that it's evaluating the one keydown event. That event will always be whatever it starts as, and there's no chance for it to change within the event handling code. What you want to catch is the PG.KEYUP event that follows it. So you'll have something (logically) like
if event.type == PG.KEYDOWN and keystate[PL.K_UP]:
key_up_pressed = True
elif event.type == PG.KEYUP and keystate[PL.K_UP]:
key_up_pressed = False
Obviously, you can factor that better, but the key_up_pressed state will get evaluated in your main loop once every so often (frame, millisecond, whatever), and move the paddle.
In this code:
while keystate[PL.K_UP]:
rightPaddle.update(-20)
… there is nothing that can change keystate. So, if keystate[PL.K_UP] is true once, it will be true forever. Hence the infinite loop.
You could fetch the current key information from pygame each time through the loop, which would at least make it not infinite—but it would still mean your entire program blocks up until the user releases the key.
Without knowing whether you intended to write a frame-rate-driven game or an event-loop-driven game, I can't tell you exactly how to fix it.
But either way, the key point is that you don't want to move over and over as long as the key is held down, you want to move at a certain speed, processing other events in between, as long as the key is held down. Either way, you'll use the KEYDOWN and KEYUP events to set some kind of flag that tells you to move the paddle. Then, once per frame, or using a timer event, or in some other way, you will use the current flag value to move the paddle.