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.
Related
I've a program to detect mouse pointer movement and move the mouse if pointer is stationary during some period. I'm using pyautogui for this purpose.
The reason for doing this is to avoid the screen being locked and I hate to type the password again and again. (No I don't have control over the settings)
This is my code for that.
import pyautogui as screen
from time import sleep
startX, startY = 1760, 10
tempX, tempY = startX, startY
while True:
posX, posY = screen.position()
if tempX == posX or tempY == posY:
screen.moveTo(startX, startY)
sleep(1)
screen.moveTo(posX, posY)
sleep(180)
tempX, tempY = posX, posY
The above code works like a charm for mouse pointer movement detection. But while long keyboard usage sessions (like coding), there is mouse pointer movements because of the above snippet and where ever the pointer goes, if there is some hover action available, that pops out.
So is there anyway to detect whether any keys have been pressed during the sleep time? I don't want to hijack the keypresses as input to python program and also don't want to actively monitor the keypresses. Just some buffer like thing which will keep on mirroring the keypresses (without hijacking) and when I wake up from sleep, check the buffer if any content is there or not and take action accordingly.
P.S.
The above code is cross platform but being used in a unix environment currently. So if any solution specific to unix will also be acceptable.
I am using pygame 1.9.6 and python 3.7.7. I am looking for a way to have something drawn by pygame(or maybe even an image) that stays inside the window border(and stops when I release the key. I started with the “if keys[]:” method:
if keys[pygame.K_LEFT] and x>0:
x-=speed
that made it stay in bounds, but it only moved a few pixels and then did not repeat.
Next I tried the “event.key” method:
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
xchange=-speed
ychange=-0
but that just makes the object move forever. I tried putting “and x>0” on the same line right after the direction, an “if x>0:” before, an “if x<0:” after, but the event never updates to see that the coordinates are past the edge, even with update commands. It just keeps going and going. I also don’t know how to make the object stop moving when I release the key, since event.key’s have the event always on.
Thank you for all the help you can offer.
In order for something to stay within a frame, you must check if it's coordinates are not past the border before moving it.
keys = pygame.key.get_pressed()
if(keys[K_LEFT]):
if(square.left > 0):
square.left -= 10
if(keys[K_RIGHT]):
if(square.right < 600):
square.left += 10
if(keys[K_UP]):
if(square.top > 0):
square.top -= 10
if(keys[K_DOWN]):
if(square.bottom < 600):
square.bottom += 10
This is an example of how you would do this with a Rect object, it checks for border and then moves the object if its within those border and the appropriate key is being pressed. I can't apply this to your code as I cannot see enough of it but you just have to replace the coordinates. For example, you might have thing.x instead of square.left
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.
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.
This question already has answers here:
Pygame how to fix 'trailing pixels'?
(4 answers)
Closed 5 years ago.
I'm trying to develop a simple game in python using pygame and IDLE. I have, since yesterday, looked through a variety of sources in order to learn about the language (and programming in general), even so I have encountered some problems and misunderstandings of how it all works. So, if anyone could please advise me on how to proceed (or point me in the direction of some good learning material) then I would appreciate it greatly.
So far, I've got a small bit of code that forms the basis of my game idea, so I will post it here and list some of my problems.
import pygame
def main():
pygame.init()
logo = pygame.image.load("coolblack.jpg")
pygame.display.set_icon(logo)
pygame.display.set_caption("Battleship")
screenWidth = 800
screenHeight = 600
screen = pygame.display.set_mode((screenWidth, screenHeight))
bgd_image = pygame.image.load("grid.png")
#--------------------------------------------------------------------
#the image named 'image' should be above 'bgd_image' but below 'cv9'
#in fact, everything should be above bgd_image, especially 'cv9'
#--------------------------------------------------------------------
image = pygame.image.load("coolblack.jpg")
cv9 = pygame.image.load("ussessexcv9.gif").convert_alpha()
xposCv9 = 400
yposCv9 = 510
step_xCv9 = 1
step_yCv9 = 1
screen.blit(bgd_image, (0,0))
screen.blit(image, (400,300))
screen.blit(cv9, (xposCv9, yposCv9))
pygame.display.flip()
clock = pygame.time.Clock()
running = True
#---------------------------------------------
#I've got a pretty good idea (sort of) about
#what is happening in the section
#below this point, however it seems that
#the image 'cv9' creates a trail of itself
#every time it moves, so how could I make it
#so that it doesn't do so?
#---------------------------------------------
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
running = False
if xposCv9>screenWidth-64 or xposCv9<0:
step_xCv9 = -step_xCv9
if yposCv9>screenHeight-64 or yposCv9<0:
step_yCv9 = -step_yCv9
xposCv9 += step_xCv9
yposCv9 += step_yCv9
screen.blit(cv9, (xposCv9, yposCv9))
pygame.display.flip()
clock.tick(60)
if __name__=="__main__":
main()
The way that pygame works is that it has internally a representation of the screen which you are updating. So, it starts entirely black, then you do your first "blit". This will update the internal representation. Then when you call "pygame.display.flip" it shows that representation on the screen. However, this will not automatically "clear" the representation for you back to all black for your next frame. So, on the next frame, you blit again (slightly to the left, say), and the first blit remains, creating your "trail".
Therefore, for what you're doing, the best thing would be to in your loop, clear the internal representation of the screen before you start drawing the next frame. You can "clear" the screen by filling it with a single color, like so...
BLACK = (0,0,0)
....
screen.blit(cv9, (xposCv9, yposCv9))
pygame.display.flip()
clock.tick(60)
screen.fill(BLACK) # Add this to "clear" the screen.
Note that if you chose to go this route, this means you will need to redraw ALL of the elements every single frame (not just the ones that changed since the last frame).
BTW, in case you are wondering, there is a good reason for why the frame is not automatically cleared at the end. In some cases, it might be faster to only update the parts of the screen that update. This can cause performance speedups in some applications. However, it's probably best to start with clearing the screen as the example shows above.