How to blit on the screen only once at mouse position - python

I have been trying to blit an image to my screen using the mouse position. This is my code.
#Placing the farm
if farm:
if pygame.mouse.get_pressed()[0]:
hi = True
if hi:
screen.blit(farm_image,mouse_pos)
So basically I want it to blit an image to screen only once at the mouse_position when the mouse is clicked., however it displays the image not once but moves with the mouse_pos. What would I do to make the image only be displayed once at the mouse_position. I do have a main loop before this.
What I have tried is setting hi to False after the image is blit, but that erases the image latter. Thank you for any answers you can provide!

Building on PythonMaster's answer something like that might work and ensure the farm remains blitted at every frame in case you refresh all your screen with a background every time:
#Placing the farm
if farm:
if pygame.mouse.get_pressed()[0] == False: #resets the first_click to False everytime the button is released
first_click = False
if pygame.mouse.get_pressed()[0]:
if first_click == False:
first_click = True
else:
pass
if first_click == True: #set's the farm position it will keep updating the position of the farm as you drag the mouse, if you do not want that set first_click to False here.
farm_pos = mouse_pos
try: #using try here, prevents errors when farm_pos is not yet defined
screen.blit(farm_image,farm_pos)
except:
print 'farm position not defined yet, click to place'

You could try using another variable to check to see if it was your first click or not:
if pygame.mouse.get_pressed()[0]:
if first_click == False:
hi = true
first_click = True
else:
pass
Make sure to define first_click before you use it. This code uses first_click to see if you clicked once already. Its starting value is False and changes to True once the mouse has clicked. This also changes hi into True while disallowing a second click as first_click is no longer False. This leads to the else and pass statements, which do practically nothing.

You can also use event checking instead of state checking when you only want a single click. This is especially useful because it means you won't miss a click (which might happen if the user clicks and releases the mouse at a moment when your code isn't checking for user input). Pygame has the events MOUSEBUTTONDOWN and MOUSEBUTTONUP which both give you the position of the mouse and the button that was clicked.
How your incorporate this into your code depends on the rest of your code, e.g. if you use the pygame event queue somewhere else already. Small example:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if farm:
screen.blit(farm_image,(event.pos[0], event.pos[1]))
You may use a variable to keep track of the state once the farm has been placed as suggested by PythonMaster and Sorade, or better yet, store the position and visible state of the farm in a farm object (Sprite) and simply blit it to its position whenever its state is set to visible.

Related

Pygame Display Update Glitch?

I have some code that is kinda funky. Basically, the variable gameStart is in a variable that uses the function, cursorOver, which finds and detects where and if the mouse button is and if it is pressed. I have 3 buttons and I want each button to become larger when the cursor is over the button. The first button implementation works. However, if I try to add another button, the button becomes enlarged, however, the button starts flickering.
window.blit(background,(0,0))
window.blit(title,(175,200))
pygame.draw.rect(window,PURPLE,(50,400,200,100),0)
pygame.draw.rect(window,PURPLE,(300,400,200,100),0)
pygame.draw.rect(window,PURPLE,(550,400,200,100),0)
close()
mouseX,mouseY = pygame.mouse.get_pos()
mouseClick = pygame.mouse.get_pressed()[0]
gameStartC = cursorOver(50,400,200,100,mouseX,mouseY)
instructionStartC = cursorOver(300,400,200,100,mouseX,mouseY)
objectiveStartC = cursorOver(550,400,200,100,mouseX,mouseY)
nextStartC = cursorOver(580,250,175,100,mouseX,mouseY)
if gameStartC == True:
while True:
pygame.draw.rect(window,PURPLE,(25,375,250,150),0)
pygame.display.update()
break
else:
pygame.draw.rect(window,PURPLE,(50,400,200,100),0)
pygame.display.update()
#this is the part where the code becomes glitchy
if instructionStartC == True:
while True:
pygame.draw.rect(window,PURPLE,(275,375,250,150),0)
pygame.display.update()
break
else:
pygame.draw.rect(window,PURPLE,(300,400,200,100),0)
pygame.display.update()
It's simply because you call pygame.display.update() multiple times.
You should create a standard game loop that typically does these three things:
handle input
update state
draw to screen
and then repeats.
In the 'draw to screen'-step, you draw all your sprites/rects/whatever to the screen surface, and then eventually call pygame.display.update() once at the end.
Calling pygame.display.update() multiple times, not clearing the screen between iterations of the loop and creating multiple unnecessary event loops are common beginner mistakes that lead to those kind of glitches IMHO.
So in your case, the code should probably look more like this:
if gameStartC:
pygame.draw.rect(window,PURPLE,(25,375,250,150),0)
else:
pygame.draw.rect(window,PURPLE,(50,400,200,100),0)
if instructionStartC:
pygame.draw.rect(window,PURPLE,(275,375,250,150),0)
else:
pygame.draw.rect(window,PURPLE,(300,400,200,100),0)
pygame.display.update()
I don't know what you expected the while-loops to do, and maybe you should use pygames Rect and Sprite classes. It will make your life easier.

Python Pygame mouse position not updating

I am trying to implement a game using mouse position to see if the user clicks a button. Somehow the mouse position does not update for a couple seconds, and changes to a new position for another couple seconds, and repeat. I moved and pressed the mouse at different location in the screen, but the mouse position did not change at all. (Working on python3.5.1 and pygame 1.9.2, using IDE PyCharm)Any idea?
Here is my code:
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if click[0]==1:
print(mouse)
pygame.display.update()
The call
mouse = pygame.mouse.get_pos()
doesn't update the position unless the event MouseMotion is executed.
If you are executing the program in a window on a MAC, the mouse must be pressed, held, and moved (if you were to press, hold, then move the mouse, pygame.mouse.get_pos() would return the current mouse position).
There is two ways of handling input events in pygame :
State Checking
Event Handling
For better understanding of how it works :
http://www.pygame.org/docs/tut/newbieguide.html#managing-the-event-subsystem
You use both in your code, state checking :
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
Event handling :
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
If you still want to use state checking to get the mouse position you can add:
clock=pygame.time.Clock()
clock.tick(60) # 60 frames per second
So the update of the position should be better.
If the button has a rect then you can use the rect.collidepoint() method with event checking like this:
mouse_pos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0] and button.rect.collidepoint(mouse_pos):
This drove me crazy for hours. I had a similar problem.
Using pygame in:
Mac OSX 10.13 (High Sierra)
pygame 1.9.3
python 3.6
in a virtualenv
In this setup (specifically in the virtualenv), window focus is not properly tracked. Click and dragging will generate a MOUSEMOTION event, but simply moving the mouse around will not. If the MOUSEMOTION event is not generated, calling:
pos = pygame.mouse.get_pos()
will continue report the same value until another MOUSEMOTION event occurs.
Installing pygame outside of the virtualenv, all works as expected. Not really the answer I was hoping for, but at least it explains the behavior I was seeing.
Your
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
only get the states at the time of the call. As per the documentation http://www.pygame.org/docs/ref/mouse.html:
to get all of the mouse events it is better to use either
pygame.event.wait() or pygame.event.get() and check all of those events
That is you are missing the clicks because your program isn't storing them to process. You only see it when you get lucky and the program calls the function when the button is actually down.
This shows a basic pygame mouse getting program. Simply click anywhere in the window and the mouse coordinate are printed:
import pygame as py
py.init()
white = (255,255,255)
window = (400,400)
screen = py.display.set_mode(window)
clock = py.time.Clock()
done = False
while not done:
for event in py.event.get():
if event.type == py.QUIT:
done = True
elif event.type == py.MOUSEBUTTONDOWN:
print py.mouse.get_pos()
screen.fill(white)
py.display.flip()
clock.tick(30)
py.quit()
hope this helps :)

`pygame.mouse.get_pressed()` reports clicks when mouse is not clicked

I am programming an experiment with Pygame 1.9.2 on Python 2.7. In the experiment, I display an image and ask the user to click either the left mouse button or right mouse button based on a feature of the image (I instruct them in advance when to click what). The image is displayed until the user clicks or if the time of image display exceeds a fixed duration.
Here's the code snippet.(Hope this bit is enough to understand what is being done.)
pygame.display.update()
resp = None
while 1:
dispEnd = time.time()
pygame.mouse.set_visible(True)
pygame.event.get()
ms = pygame.mouse.get_pressed()
if ms[0] or ms[2]:
rt = dispEnd - dispSt
if ms[0]:
resp = 'Yes'
else:
resp = 'No'
break
if dispEnd - dispSt >= changeDuration:
break
This piece of code is part of a bigger loop where an image is selected and displayed, so this runs several times.
What happens at unpredictable times is that the program does not wait for user input. Right after displaying the image, it enters the while loop and proceeds as if the mouse were pressed.
It's a random error and happens anytime; sometimes right at the start of the program, from the very first run of the loop; so probably it is not because of the event queue possibly not being cleared (which it is while calling pygame.event.get()) and it also cannot be defaulting to the previous mouse click; sometimes it happens after a few iterations of the loop. Either way, it is disastrous for an experiment.
Try this out:
...
while 1:
dispEnd = time.time()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
#do something
...

Why is my pause system not working in Pygame?

Here's my check_for_pause() function:
#Check if the user is trying to pause the game
def check_for_pause():
keys=pygame.key.get_pressed() #Get status of all keys
if keys[K_SPACE]: #The space bar is held down
global paused #Make global so it can be edited
if paused==True: #It was paused, so unpause it
paused=False
elif paused==False: #It was playing, so pause it
paused=True
#Don't let the main loop continue until the space bar has been released again, otherwise the variable will flicker between True and False where the loop runs so fast!
space_bar_pressed=keys[K_SPACE]
while space_bar_pressed: #Repeat this loop until space_bar_pressed is False
keys=pygame.key.get_pressed()
if not keys[K_SPACE]: #Space bar has been released so set space_bar_pressed to False
space_bar_pressed=False
however this keeps making my program become unresponsive whenever I try to pause it! Basically, I want the variable "paused" to be either True or False. When the space bar is pressed, it should change to whichever one it isn't currently. Because I'm using check_for_pause() in another never-ending loop, I need to make it so that the function only stops executing when the space bar is released, otherwise if the user holds the space bar for more than a split second it will keep switching between True and False.
Any ideas why my program becomes unresponsive when I run this? I know it's to do with the bit that waits until the space bar's been released because when I remove that bit of the code then my program runs fine (but obviously the pause feature then doesn't work).
You have a main loop that probably looks something like this...
while True:
check_for_pause()
# Update the game
# Draw the game
When you check for pause, and the space key is pressed down, paused gets set to True. Then, you have this loop...
space_bar_pressed=keys[K_SPACE]
while space_bar_pressed: #Repeat this loop until space_bar_pressed is False
keys=pygame.key.get_pressed()
if not keys[K_SPACE]: #Space bar has been released so set space_bar_pressed to False
space_bar_pressed=False
The problem with this loop is that you assume that pygame.key.get_pressed() will continue to return up-to-date information. However, looking at the pygame source code, it appears that it uses SDL_GetKeyState, which says as part of its documentation..
Note: Use SDL_PumpEvents to update the state array.
In other words, repeatedly calling pygame.key.get_pressed() will NOT give you the updated key state if you are not additionally calling something like pygame.event.pump(), which actually updates pygame with the new key states. So, you could quickly fix this by introducing that pump function into the loop, as currently it is just running forever.
That being said: DON'T DO THIS. If you do it this way, your game will not be able to do ANYTHING when paused: this includes showing a "paused" screen, continuing to play the music in the background, etc. What you want to do instead is keep track of if the game is paused, and if so, change how the game is updating.
In the part of your game where you update things, some items should only happen if the game is paused. Something like...
paused = False
while True:
# This function should just return True or False, not have a loop inside of it.
paused = check_for_paused()
if not paused:
# This function moves your enemies, do physics, etc.
update_game()
draw_game()
In this case, the main loop will still happen, the game will continue to be drawn, and the input will continue to be handled. However, the enemies and players will not be moving, therefore the game can be said to be "paused".
Finally, there is also the fact that you're relying on get_key_pressed(), which you probably don't want to do. See this other similar answer I've given for reasons why you should be instead using the event queue.
You should never stop running your game loop in a game even if it paused. Also pauses are generally handled through events. For example look at this code:
import pygame, sys
from pygame.locals import *
pygame.init()
pygame.display.set_mode((400,400))
paused = False # global
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_SPACE:
paused = not paused
if paused:
continue # skip this iteration if paused
# add your game code here
print 'game code running'
In the above code, I toggle paused every time I press spacebar. If you want to pause only while holding spacebar do this:
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type in (KEYDOWN, KEYUP): # checks membership in tuple
if event.key == K_SPACE:
paused = not paused
if paused:
continue # skip this iteration if paused
# add your game code here
print 'game code running'
As a general note, you should always be handling events from your event queue or Pygame will just cry and whine and do nothing (be unresponsive). Thus, never stop spinning on your game loop even if you have paused the game.
EDIT: Alternatively, as abarnert pointed out in the comments you can do a trick with equality comparisons to assure that you never get conflicts between KEYDOWN and KEYUP events:
paused = event.type == KEYDOWN
This way you won't have "syncing problems" where the code accidentally sets paused to True whenever you actually release the spacebar. This can happen if 2 KEYDOWN events happen in a row or if 2 KEYUP events happen in a row (instead of a smooth alternating sequence like KEYDOWN, KEYUP, KEYDOWN, KEYUP, etc.). It's best to not assume that all event queues feed events that are 100 percent accurate.

Pygame: Sprite changing due to direction of movement

I've just started learning how to use pygame yesterday. I was read this one book that was super helpful and followed all its tutorials and examples and stuff. I wanted to try making a really simple side scroller/platforming game but the book sorta jumped pretty fast into 3D modeling with out instructing how to make changing sprites for movement of up down left and right and how to cycle through animating images.
I've spent all today trying to get a sprite to display and be able to move around with up down left and right. But because of the simple script it uses a static image and refuses to change.
Can anyone give me some knowledge on how to change the sprites. Or send me to a tutorial that does?
Every reference and person experimenting with it ha always been using generated shapes so I'm never able to work with them.
Any help is very appreciated.
Added: before figuring out how to place complex animations in my scene I'd like to know how I can make my 'player' change to unmoving images in regards to my pressing up down left or right. maybe diagonal if people know its something really complicated.
Add: This is what I've put together so far. http://animania1.ca/ShowFriends/dev/dirmove.rar would there be a possibility of making the direction/action set the column of the action and have the little column setting code also make it cycle down in a loop to do the animation? (or would that be a gross miss use of efficiency?)
Here is a dumb example which alernates between two first images of the spritesheet when you press left/right:
import pygame
quit = False
pygame.init()
display = pygame.display.set_mode((640,480))
sprite_sheet = pygame.image.load('sprite.bmp').convert()
# by default, display the first sprite
image_number = 0
while quit == False:
event = pygame.event.poll()
no_more_events = True if event == pygame.NOEVENT else False
# handle events (update game state)
while no_more_events == False:
if event.type == pygame.QUIT:
quit = True
break
elif event.type == pygame.NOEVENT:
no_more_events = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
image_number = 0
elif event.key == pygame.K_RIGHT:
image_number = 1
event = pygame.event.poll()
if quit == False:
# redraw the screen
display.fill(pygame.Color('white'))
area = pygame.Rect(image_number * 100, 0, 100, 150)
display.blit(sprite_sheet, (0,0), area)
pygame.display.flip()
I've never really used Pygame before so maybe this code shoudln't really be taken as an example. I hope it shows the basics though.
To be more complete I should wait some time before updating, e.g. control that I update only 60 times per second.
It would also be handy to write a sprite class which would simplify your work. You would pass the size of a sprite frame in the constructor, and you'd have methodes like update() and draw() which would automatically do the work of selecting the next frame, blitting the sprite and so on.
Pygame seems to provide a base class for that purpose: link text.
dude the only thing you have to do is offcourse
import pygame and all the other stuff needed
type code and stuff..........then
when it comes to you making a spri
class .your class nam here. (pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.init(self)
self.image=pygame.image.load(your image and path)
self.rect=self.image.get_rect()
x=0
y=0
# any thing else is what you want like posistion and other variables
def update(self):
self.rect.move_ip((x,y))
and thats it!!!! but thats not the end. if you do this you will ony have made the sprite
to move it you need
I don't know much about Pygame, but I've used SDL (on which Pygame is based).
If you use Surface.blit(): link text
You can use the optional area argument to select which part of the surface to draw.
So if you put all the images that are part of the animation inside a single file, you can select which image will be drawn.
It's called "clipping".
I guess you will have a game loop that will update the game state (changing the current image of the sprite if necessary), then draw the sprites using their state.

Categories