How to keep my blitted image on screen once thy are created - python

I am making a simple tic tac toe game in which there is an image that I blit on a mouse up event...but due to the game loop, it disappears the very next moment. Here is the code...can anybody help me on how to keep it on-screen once it is blitted by the mouse..
toggle = True
# Game loop.
while True:
box = 0
...
if event.type == pygame.MOUSEBUTTONUP:
pos = pygame.mouse.get_pos()
if rect_1.collidepoint(pos):
box = 1
toggle = not toggle
...
screen.fill((235, 235, 235))
if box != 0:
if (toggle):
if (box == 1):
cross_rect = cross_minified.get_rect(center=rect_1.center)
screen.blit(cross_minified, cross_rect)
can anyone please suggest me a solution please?

Initailize box above the loop:
toggle = True
# Game loop.
box = 0
while True:
...

I Got the Solution Guys, I simply used a list and check if the value is appended or not and if appended I just blitted it to the screen.

Related

surface_obj.fill('color') function is causing error [duplicate]

This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 6 months ago.
i am trying to make hangman with pygame
1 > if you copy following code in IDE and run it will prompt pygame window if you clicked inside button(circles) it will basically disappear . Like in typical hangman game
2> BUT if you comment line < win.fill('darkred')> then code will stop working , meaning button(circles) will no more disappear
** can anyone tell why? **
import pygame , math
pygame.init()
WIDTH , HEIGHT = 900 , 600
win = pygame.display.set_mode((WIDTH , HEIGHT))
pygame.display.set_caption('Hangmane')
RUN = True
# indexing button coordinates and appending in letters(list)
letters = [ ]
RADIUS = 20
BUTTON_X = 0
BUTTON_Y = 457
for i in range(26):
BUTTON_X += 60
if i == 14:
BUTTON_X = 100
BUTTON_Y = 520
#pygame.draw.circle(win,'green',(BUTTON_X,BUTTON_Y),RADIUS,3)
letters.append([BUTTON_X, BUTTON_Y])
#drawing button(circle) in pygame window
def button():
for letter in letters:
BUTTON_X , BUTTON_Y = letter
pygame.draw.circle(win,'green',(BUTTON_X,BUTTON_Y),RADIUS,3)
# this will check and remove if button(circle) is clicked
def click_checker(coordinates):
letters.remove(coordinates)
while RUN:
win.fill('darkred') #if you comment this than code will not work as intended
button()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUN = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos_x , pos_y = pygame.mouse.get_pos()
print(pos_x , pos_y)
for letter in letters:
BUTTON_X , BUTTON_Y = letter
dis = math.sqrt((BUTTON_X-pos_x)**2 + (BUTTON_Y-pos_y)**2)
if dis < RADIUS: # this will check if distance between mouse Cursor is less than button(circle) radius
#print('clicked')
click_checker(letter)
pygame.quit()
You should first understand how the code works inside the while RUN: loop:
The window is filled with dark red erasing any previous buttons, and green buttons are drawn using the x and y coordinates in the letters list.
On every press, if a button is pressed, then the button's x and y coordinates are removed from the letters list.
If button is not pressed, then nothing is removed from the letters list.
Now, go to step 1 again.
If you comment out win.fill('darkred') then the window will not be painted over, hence the previous buttons are not erased. So even though it will only redraw 25 buttons, the other button is still visible from the previous drawing.

Pygame: pygame.mouse.get_pos() tuple out of range?

I'm attempting to create a pygame Tic-Tac-Toe game. My issue is in my 'mousemovement()' method. Whenever i use the 'pygame.mouse.getpos()' in my 'collidepoint()' method it gives me a type error and says that my tuples index is out of range. Anyone have any ideas?
import pygame
pygame.init()
pygame.font.init()
pygame.display.set_caption("Tic-Tac-Toe")
pygame.mouse.set_visible(True)
FPS = 60
clock = pygame.time.Clock()
WIDTH,HEIGHT = 500,600
BORDER_THICKNESS = 10
WIN = pygame.display.set_mode((WIDTH,HEIGHT))
#delcare the fonts of the characters
GAME_FONT = pygame.font.SysFont("comicsans",100)
#colors
WHITE = (255,255,255)
BLACK = (0,0,0)
GREEN = (0,255,0)
def display_window(squares,marks,turn):
WIN.fill(WHITE)
starting_pos = WIDTH // 3
for l in range(2): #draws the board
vert = pygame.Rect((starting_pos - BORDER_THICKNESS//2,0),(BORDER_THICKNESS,HEIGHT))
hrzn = pygame.Rect((0,starting_pos - BORDER_THICKNESS//2),(WIDTH,BORDER_THICKNESS))
starting_pos = starting_pos * 2 + BORDER_THICKNESS//2
pygame.draw.rect(WIN,BLACK,vert)
pygame.draw.rect(WIN,BLACK,hrzn)
#draws black background for text box
more_border = pygame.Rect((0,WIDTH),(WIDTH,HEIGHT - WIDTH))
pygame.draw.rect(WIN,BLACK,more_border)
#draws actual text box
text_box = pygame.Rect((0+BORDER_THICKNESS,WIDTH+BORDER_THICKNESS),(WIDTH-BORDER_THICKNESS*2,HEIGHT - WIDTH))
pygame.draw.rect(WIN,WHITE,text_box)
#display game squares
for s in squares:
pygame.draw.rect(WIN,GREEN,s)
#prints the marks of x's and o's
for m in marks:
pass #still working on printing the marks
pygame.display.update()
#use the mouse methods in order to retrive location in which
#mouse is at and see if it collides with a given square
def mouse_movement(squares,mouse_presses,marks,turn):
for s in squares:
if s.collidepoint(pygame.mouse.get_pos()) and mouse_presses[pygame.MOUSEBUTTONDOWN]:
if turn % 2 == 1:
marks[squares.index(s)] = 'X'
elif turn % 2 == 0:
marks[squares.index(s)] = 'O'
else:
raise TypeError("Neither condition is being met")
def main():
turn = 1
x, y = 0,0
squares = []
for c in range(3):
for r in range(3):
squares.append(pygame.Rect((x,y),(WIDTH//3-BORDER_THICKNESS//2,WIDTH//3-BORDER_THICKNESS//2)))
x += WIDTH//3 - BORDER_THICKNESS//2 + BORDER_THICKNESS
x = 0
y += WIDTH//3 - BORDER_THICKNESS//2 + BORDER_THICKNESS
marks = ['','','','','','','','','']
game_going = True
while game_going:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_going = False
pygame.quit()
print(pygame.mouse.get_pos())
mouse_presses = pygame.mouse.get_pressed()
marks = mouse_movement(squares,mouse_presses,marks,turn)
display_window(squares,marks,turn)
if __name__ == '__main__':
main()
I searched the pygame website to make sure that the 'pygame.mouse.get_pos()' method returns a tuple and it does. I'm not quite sure where to go from here.
You get the out of range exception because of mouse_presses[pygame.MOUSEBUTTONDOWN].
pygame.mouse.get_pressed() returns a list of Boolean values ​​that represent the state (True or False) of all mouse buttons. The state of a button is True as long as a button is held down. When multiple buttons are pressed, multiple items in the list are True. The 1st, 2nd and 3rd elements in the list represent the left, middle and right mouse buttons.
If you want to test if the left mouse button is pressed it is:
if mouse_presses[0]:
If you want to test if any button is pressed it is:
if any(mouse_presses):
However, this is not how the MOUSEBUTTONDOWN event works. The MOUSEBUTTONDOWN event occurs once when you click the mouse button and the MOUSEBUTTONUP event occurs once when the mouse button is released. The pygame.event.Event() object has two attributes that provide information about the mouse event. pos is a tuple that stores the position that was clicked. button stores the button that was clicked. Each mouse button is associated a value. For instance the value of the attributes is 1, 2, 3, 4, 5 for the left mouse button, middle mouse button, right mouse button, mouse wheel up respectively mouse wheel down. When multiple keys are pressed, multiple mouse button events occur. Further explanations can be found in the documentation of the module pygame.event.
e.g.:
game_going = True
while game_going:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_going = False
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # left button
print(event.pos) # mouse position
# [...]

Can't click on image again, what's wrong with my pygame code?

Okay, I'am trying to create a Tom and Jerry game with the pygame library.
The game focuses on catching mice by clicking on them as they appear in their holes. The problem
is that sometimes a cat appears instead of a mouse and should the player erroneously click on the
cat (s)he looses all earned points, but the game continues.
The mouse is an image of a mouse and the cat is an image of an cat.
If you click on the mouse, you get mouse, otherwise the cat gets the points.
The code is a mess, that's because I don't know what I'am doing and just set an another event loop because then it works, because it runs after I create the mouse. It works to click on the mouse but then you click somewhere else and after that it's like you did not clicked on the mouse.
The mouse is created in a loop and is supposed to wait for 5 seconds and if you click on the mouse within these seconds then an appropriate message prints out in the console ,,Jerry clicked!" else "1 click". If you don't click on the mouse within 5 seconds a image covers the mouse so she disappears.
Now, what I'am trying to do right now is to print the message 1 click when the player does not click on anything but print 1 click jerry clicked when the player clicks on the mouse. I have a image of the mousehole and then I put the mouse on the mousehole, that is, on an another image.
This code works with one image at least:
pygame.init()
width=350;
height=400
screen = pygame.display.set_mode( (width, height ) )
pygame.display.set_caption('clicked on image')
redSquare = pygame.image.load("images/red-square.png").convert()
x = 20; # x coordnate of image
y = 30; # y coordinate of image
screen.blit(redSquare , ( x,y)) # paint to screen
pygame.display.flip() # paint screen one time
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
if redSquare.get_rect().collidepoint(x, y):
print('clicked on image')
#loop over, quite pygame
pygame.quit()
My problem is that, when I click on the mouse and then I don't click on the mouse I can't click on the mouse again at another position.
So what's wrong? What I'am doing wrong here?
Here is my code:
import pygame
from pygame import *
from random import *
init()
run = True
screen = (800,800)
screen = display.set_mode(screen)
xpos = 0
ypos = 0
mouseorcatxpos = 5
mouseorcatypos = 0
mousehole = image.load("mousehole.png").convert()
cat = image.load("tom.png")
jerry = image.load("jerry.png")
def makeholes():
global ypos
global xpos
for holey in range(1,9):
for holex in range(1,9):
screen.blit(mousehole,(xpos,ypos))
display.flip()
xpos += 100
ypos += 100
xpos = 0
def mouseorcat():
global xpos
mouseorcatxpos = 5
ypos = 0
for mousecaty in range(1,9):
pygame.event.pump()
for mousecatx in range(1,9):
randommouse = randint(1, 3)
randomcat = randint(1, 10)
if(randommouse == 2):
screen.blit(jerry, (mouseorcatxpos, ypos))
display.flip()
for event in pygame.event.get():
if (event.type == MOUSEBUTTONDOWN):
if jerry.get_rect().collidepoint(xpos, ypos) == False:
print("l clicked!")
x, y = event.pos
if jerry.get_rect().collidepoint(xpos, y):
print("JERRY CLICKED!!")
x, y = event.pos
print(x, y)
time.wait(5000)
#screen.blit(mousehole, (mouseorcatxpos - 5, ypos))
display.flip()
elif(randomcat == 2):
screen.blit(cat, (mouseorcatxpos, ypos))
display.flip()
time.wait(1500)
screen.blit(mousehole, (mouseorcatxpos-5, ypos))
display.flip()
mouseorcatxpos += 100
mouseorcatxpos = 0
ypos += 100
makeholes()
while run == True:
for event in pygame.event.get():
mouseorcat()
if event.type == QUIT:
run = False
I rewrote your game to show you how I would do it.
To keep track of the time and to limit the framerate I used a pygame.time.Clock and a timer variable. The clock returns the time in milliseconds since clock.tick was called the last time, which is used to increase the timer variable. The cat just replaces the mouse after two seconds and the mouse is set to a new position. I use pygame.Rects to store the positions, but you could also use lists or tuples.
import sys
import random
import pygame
pygame.init()
size = (800, 800)
screen = pygame.display.set_mode(size)
# Images replaced by pygame.Surface. Do that too
# in the future before you post your code.
mousehole = pygame.Surface((40, 40)).convert()
mousehole.fill(pygame.Color(30, 30, 30))
cat = pygame.Surface((40, 40)).convert()
cat.fill(pygame.Color(110, 110, 130))
jerry = pygame.Surface((40, 40)).convert()
jerry.fill(pygame.Color(190, 130, 0))
# Create the background image and blit the holes.
background = pygame.Surface(size).convert()
for holey in range(8):
for holex in range(8):
background.blit(mousehole, (holex*100, holey*100))
def new_position():
"""Return a random position between 0-700 in steps of 100."""
return (random.randrange(0, 701, 100), random.randrange(0, 701, 100))
def main():
fps = 30
clock = pygame.time.Clock()
jerry_rect = jerry.get_rect() # Stores jerry's position and size.
jerry_rect.topleft = new_position() # New random position.
# The cat is outside of the screen first.
cat_rect = cat.get_rect(topleft=(-100, -100))
points = 0
timer = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if jerry_rect.collidepoint(event.pos):
points += 1
print('Jerry caught! Points:', points)
timer = 0
jerry_rect.topleft = new_position()
else:
print('Missed. Points:', points)
# Run logic.
timer += clock.tick(fps) / 1000 # timer + seconds since last tick.
if timer > 2: # Cat catches mouse after 2 seconds.
cat_rect.topleft = jerry_rect.topleft
jerry_rect.topleft = new_position()
timer = 0
points = 0
print('Tom caught Jerry.')
# Draw.
# Clear the screen by blitting the bg.
screen.blit(background, (0, 0))
screen.blit(jerry, jerry_rect)
screen.blit(cat, cat_rect)
pygame.display.flip()
if __name__ == '__main__':
main()
pygame.quit()
sys.exit()
Side notes:
Don't use star imports (from module import *), because that can make code harder to read. If you want you can use from pygame.locals import *, if it's the only star import.
Don't use global variables, because they can make code harder to read, understand and maintain. Pass variables to functions as arguments and then return the result.
Update: Some notes about your program:
The first big problem is that your game has two event loops and the important one is deeply nested inside of two other for loops and a if. The event loop should be directly under the main while loop (one indentation level (when you have more experience you can put it into a function or class method)).
The two for loops seem to have the purpose to let the code run until randommouse or randomcat are 2. To run code until a condition is met is the purpose of a while loop. But in this case you should better just pick a random number and write the if/elif conditions so that they always apply. For example, you want a 2/3 chance for mouse and 1/3 for a cat,
random_number = random.randint(1, 3)
if random_number < 3:
print("2/3 probability. It's a mouse")
else:
print("1/3 probability. It's a cat")
Or use random.choice with a list:
>>> random.choice(['mouse', 'mouse', 'cat'])
'mouse'
time.wait(5000) shouldn't be used because the game just hangs in this time. You can't even close the window. Limit the framerate and get the time since the last tick with a pygame.time.Clock.
pygame.event.pump() is not needed.
If you call get_rect() without an argument, the rect is positioned at (0, 0).
if jerry.get_rect().collidepoint(xpos, y):
That's the reason why clicking on jerry only works in the top row, and because you use the global xpos here. Since xpos is 0, the whole top row counts as Jerry.
You can pass coordinates to get_rect like so (you can also use center or other args instead of topleft):
jerry_rect = jerry.get_rect(topleft=(50, 100))
I'm sorry but I don't think I can simply fix your code. I've tried it several times, but I always end up re-writing it completely.
I begin by extracting the event loop out of the two nested for loops, then remove these loops, create rects for the mouse and cat, fix the collision detection, add a timer and so on. Take a close look at my example and try to rewrite your game in a similar way, and keep asking questions if you don't understand something.

Moving an image in PyGame hides all of the other images

When I move an image around my PyGame screen, if it happens to pass over another image, those onderneath get hidden and cannot be seen again. Why might this be?
My code is:
def main():
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
background = pygame.image.load('Background.png').convert()
screen.blit(background, (0, 0)) # draw the background screen
human1 = pygame.image.load('Human1.gif').convert()
human1_position = pygame.Rect(10, BOTTOM_FLOOR, CHARACTER_WIDTH, CHARACTER_HEIGHT)
screen.blit(human1, human1_position) # draw the first human
human2 = pygame.image.load('Human2.gif').convert()
human2_position = pygame.Rect(100, BOTTOM_FLOOR, CHARACTER_WIDTH, CHARACTER_HEIGHT)
screen.blit(human2, human2_position) # draw the second human
human3 = pygame.image.load('Human3.gif').convert()
human3_position = pygame.Rect(190, BOTTOM_FLOOR, CHARACTER_WIDTH, CHARACTER_HEIGHT)
screen.blit(human3, human3_position) # draw the third human
pygame.display.update() # display all graphical elements
move = STOP # Variable to track what the current move is. Initially, stopped
move_character = 1 # Variable to track which character is being moved
while True:
#
# See what the user did...
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
# Check if there is a move currently happening. The program
# will only do something if the previous move is stopped
if move == STOP:
# Check which key was pressed...
if event.key == pygame.K_1:
# if key pressed is the '1' key, move first human (and check if moving from bottom to top or other way)
move_character = 1 # the first character is to be moved
if human1_position.top < 300:
# If the 'top' of the human's position is less
# than 300 then it means the human is currenlty
# on the top half of the screen, and so
# the next move will be to move it downards
move = DOWN
else:
move = UP
# Check which key was pressed...
if event.key == pygame.K_2:
# if key pressed is the '2' key, move second human (and check if moving from bottom to top or other way)
move_character = 2 # the first character is to be moved
if human2_position.top < 300:
# If the 'top' of the human's position is less
# than 300 then it means the human is currenlty
# on the top half of the screen, and so
# the next move will be to move it downards
move = DOWN
else:
move = UP
screen.blit(background, human1_position, human1_position) # erase old position of first human
if (move == UP):
#they want to move up, so first check the lift is down with them.
if (liftLoc == "down"):
#they are both down, they can be moved into the lift
if (human1_position.left <= 245):
human1_position = human1_position.move(2, 0) # move first human
pygame.display.update()
else:
move = STOP
else:
print "Wrong floor!"
So the problem you are having, is that you are only rendering/blitting the images you move over when you start, so they get "unrendered" or rendered over.
To get rid of this problem, like all other real time rendering engines, you should render everything you want someone to see, every frame you want something to happen.
I shall not give you the code correction, but just moving the screen.blit of every image into your while loop. Their position will obviously affect the rendering order.

Menu problem with PyGame MOUSEBUTTONDOWN event

Yes, that title wasn't worded very properly at all.
Ok, here's what we've got - a Python program using the pyGame library, and we're making a game. We start in a menu environment main.py. When the user clicks on one of the menu buttons, an action is performed. The program checks for clicks on menu items using the following code:
if event.type == pygame.MOUSEBUTTONDOWN:
mousePos = pygame.mouse.get_pos()
for item in buttons: # For each button
X = item.getXPos() # Check if the mouse click was...
Y = item.getYPos() # ...inside the button
if X[0] < mousePos[0] < X[1] and Y[0] < mousePos[1] < Y [1]:
# If it was
item.action(screen) # Do something
When the user clicks on the "Play Game" button, it opens a sub-module, playGame.py. In this sub-module is another pyGame loop etc.
Part of the game is to hold the left mouse button to 'grow' circles out of the current position (It's a puzzle game, and it makes sense in context). Here is my code for doing this:
mouseIsDown == False
r = 10
circleCentre = (0,0)
[...other code...]
if mouseIsDown == True:
# This grown the circle's radius by 1 each frame, and redraws the circle
pygame.draw.circle(screen, setColour(currentColourID), circleCentre, r, 2)
r += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
runningLevel = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# User has pressed mouse button, wants to draw new circle
circleCentre = pygame.mouse.get_pos()
mouseIsDown = True
elif event.type == pygame.MOUSEBUTTONUP:
# Stop drawing the circle and store it in the circles list
mouseIsDown = False
newCircle = Circle(circleCentre, r, currentColourID)
circles.append(newCircle)
circleCount += 1
r = 10 # Reset radius
The problem I have is that the user's left mouse click from the main menu is persisting into the playGame.py module, and causing it to create and store a new circle, of radius 10 and at position (0,0). Both of these are the default values.
This only happens for the one frame after the menu.
Is there any way to prevent this, or is it a flaw in my code?
All help greatly appreciated, as always. If you need more code or explanation of these snippets, let me know.
If you'd like the full code, it's on GitHub.
You could use MOUSEBUTTONUP instead of MOUSBUTTONDOWN in the menu.
Does adding pygame.event.clear() to the top of Play fix it?

Categories