Pygame how to "place" an image when you press a key - python

import pygame, random, time
class Game(object):
def main(self, screen):
bg = pygame.image.load('data/bg.png')
select = pygame.image.load('data/select.png')
block1 = pygame.image.load('data/enemy1.png')
clock = pygame.time.Clock()
while 1:
clock.tick(30)
spriteList = []
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
spriteList.append(block1, (0, 0))
mouse = pygame.mouse.get_pos()
print(mouse)
screen.fill((200, 200, 200))
screen.blit(bg, (0, 0))
screen.blit(select, (mouse))
for sprite in spriteList:
screen.blit(sprite[0], sprite[1])
pygame.display.flip()
if __name__ == '__main__':
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Sandbox')
Game().main(screen)
I'm trying to make it so where you move the mouse a box follows it. Then when you click the space key, "place" an image where you pressed space and then leave it there and be able to place another image somewhere else without effecting the first one. I tried using spriteList but I am kind of confused on where to go from here.
And when I run it I get an error saying: .append() takes one argument (2 given)

Add a tuple to your list. Also, store the mouse position, not (0, 0). Change
spriteList.append(block1, (0, 0))
to
spriteList.append((block1, mouse))
Also, you could rewrite
for sprite in spriteList:
screen.blit(sprite[0], sprite[1])
to
for (img, pos) in spriteList:
screen.blit(img, pos)

Related

the player is shaking when walking [duplicate]

So I run the code and it just starts glitching out. I am new to pygame.
Here is the code:
import pygame
pygame.init()
# Screen (Pixels by Pixels (X and Y (X = right and left Y = up and down)))
screen = pygame.display.set_mode((1000, 1000))
running = True
# Title and Icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('Icon.png')
pygame.display.set_icon(icon)
# Player Icon/Image
playerimg = pygame.image.load('Player.png')
playerX = 370
playerY = 480
def player(x, y):
# Blit means Draw
screen.blit(playerimg, (x, y))
# Game loop (Put all code for pygame in this loop)
while running:
screen.fill((225, 0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# if keystroke is pressed check whether is right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("Left arrow is pressed")
if event.key == pygame.K_RIGHT:
print("Right key has been pressed")
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
print("kEYSTROKE RELEASED")
# RGB (screen.fill) = red green blue
player(playerX, playerY)
pygame.display.update()
The image is not the glitching one as I was not able to post a video but it is what my code does
The problem is caused by multiple calls to pygame.display.update(). An update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering.
Remove all calls to pygame.display.update() from your code, but call it once at the end of the application loop:
while running:
screen.fill((225, 0, 0))
# pygame.display.update() <---- DELETE
# [...]
player(playerX, playerY)
pygame.display.update()
If you update the display after screen.fill(), the display will be shown filled with the background color for a short moment. Then the player is drawn (blit) and the display is shown with the player on top of the background.

Why does my sprite reset to the top left of the screen when I try to rotate it with pygame.transform.rotate? [duplicate]

This question already has answers here:
How do I rotate an image around its center using Pygame?
(6 answers)
Closed 1 year ago.
I'm trying to rotate a sprite 90 degrees whenever the player presses the A and D keys, and I've got that working, but the sprite is always sent to the top left corner of the screen whenever this happens. Can someone shed some light on this? As well as that, I've tried to get a shooting system working with shooting asteroids, by creating an asteroid and appending it to a list, but it seems to become a tuple instead of a pygame rectangle when I try to change the y of it, can someone help with that as well?
import pygame, sys, random
from pygame.locals import *
#Imports pygame, system and random as modules to use later in the code.
#Also imports extra stuff from pygame that contains useful variables.
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
#Initialises pygame, sets up the clock to stop the program running too fast
#And also makes the font (must happen after pygame initialises)
WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite
def terminate():
pygame.quit()
sys.exit()
def pendingKey():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
return
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOUR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
#Defining functions, to quit pygame and the system.
#And to wait for the escape key to be pressed to start the terminate function.
#And to wait for the quit event (such as at the end of the game).
#And a function to create text on the screen, such as for the title.
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
#Creates the games window, sets the name of the window, and makes the mouse invisible
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
pendingKey()
#Sets the colour of the background and draws the title and some basic instructions
#And updates the display and activates the terminate function
while True:
LEFT = RIGHT = UP = DOWN = SHOOT = LEFTROTATE = RIGHTROTATE = False
#Sets the players start position to half through the screen, and 50 pixels down
#And sets the movement variables to false
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
#Checks for events, first event being the game quitting
if event.type == KEYDOWN:
if event.key == K_LEFT:
RIGHT = False
LEFT = True
if event.key == K_RIGHT:
LEFT = False
RIGHT = True
if event.key == K_UP:
DOWN = False
UP = True
if event.key == K_DOWN:
UP = False
DOWN = True
if event.key == K_SPACE:
SHOOT = True
if event.key == K_a:
RIGHTROTATE = False
LEFTROTATE = True
if event.key == K_d:
LEFTROTATE = False
RIGHTROTATE = True
#Checks for keys being pressed, corresponding to movement.
if event.key == K_ESCAPE:
terminate()
#Checks for escape being pressed, which quits the game.
if event.type == KEYUP:
if event.key == K_ESCAPE:
terminate()
if event.key == K_LEFT:
LEFT = False
if event.key == K_RIGHT:
RIGHT = False
if event.key == K_UP:
UP = False
if event.key == K_DOWN:
DOWN = False
if event.key == K_SPACE:
SHOOT = False
if event.key == K_a:
RIGHTROTATE = False
LEFTROTATE = False
if event.key == K_d:
LEFTROTATE = False
RIGHTROTATE = False
#Checks whether keys have been let go of.
if LEFT and PLAYERRECT.left > 0:
PLAYERRECT.move_ip(-1 * PLAYERSPEED, 0)
if RIGHT and PLAYERRECT.right < WINDOWWIDTH:
PLAYERRECT.move_ip(PLAYERSPEED, 0)
if UP and PLAYERRECT.top > 0:
PLAYERRECT.move_ip(0, -1 * PLAYERSPEED)
if DOWN and PLAYERRECT.bottom < WINDOWHEIGHT:
PLAYERRECT.move_ip(0, PLAYERSPEED)
if SHOOT:
ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
if LEFTROTATE:
PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, 90)
PLAYERRECT = PLAYERIMAGE.get_rect()
if RIGHTROTATE:
PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, -90)
PLAYERRECT = PLAYERIMAGE.get_rect()
for asteroid in ASTEROIDS:
asteroid.y -= 4
for asteroid in ASTEROIDS:
WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
#Moves the player a certain number of pixels in a direction and shoots asteroids
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
WINDOWSURFACE.blit(PLAYERIMAGE, PLAYERRECT)
pygame.display.update()
mainClock.tick(FPS)
#Fills the background, draws the players image on the rectangle
#And updates the screen and selects how many frames per second the game should tick by
Thanks in advance
Note that you should only call pygame.event.get() once in your application.
When you rotate, you set your player rect as such:
PLAYERRECT = PLAYERIMAGE.get_rect()
You have never specified the value of PLAYERIMAGE.get_rect() and it is (0, 0) by default, so if the player is transported to the top left of the screen. To fix that, simply remove it, it serves no purpose.
Also, your movement code can be simplified.
keys = pygame.key.get_pressed()
PLAYERRECT.move_ip
(
(keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED,
(keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED
)
Thats it.
Code to handle rotation can be simplified as well. Make a function that gets the players rotation angle:
def getPlayerRotation(keys):
if keys[K_a]: return 90
elif keys[K_d]: return -90
return 0
Then use that to rotate your image and draw it.
#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
WINDOWSURFACE.blit(rotated_image, new_rect)
Your asteroid isn't drawing because you are trying to draw it before you clear the screen, which draws over the asteroids.
Also you cannot do
ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
because there is only one asteroid.rect object, so what you are appending is a reference to the same object over and over. You need to create a new rect if your want to use a rect, but I got around the problem by using a list.
ASTEROIDS.append(list(PLAYERRECT.center))
and then later:
for asteroid in ASTEROIDS:
asteroid[1] -= 4
Lastly I changed pending key function:
def pendingKey(events):
for event in events:
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
It takes events as argument to avoid calling pygame.event.get() in the function. I also removed the return statement at the end of it since it was causing the function to exit before it got to to through all the events.
Here is the new code:
import pygame, sys, random
from pygame.locals import *
WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite
def terminate():
pygame.quit()
sys.exit()
def pendingKey(events):
for event in events:
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOUR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
def getPlayerRotation(keys):
if keys[K_a]: return 90
elif keys[K_d]: return -90
return 0
while True:
events = pygame.event.get()
pendingKey(events)
keys = pygame.key.get_pressed()
PLAYERRECT.move_ip((keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED, (keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED)
#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
for event in events:
if event.type == KEYDOWN and event.key == K_SPACE:
ASTEROIDS.append(list(PLAYERRECT.center))
for asteroid in ASTEROIDS:
asteroid[1] -= 4
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
WINDOWSURFACE.blit(rotated_image, new_rect)
for asteroid in ASTEROIDS:
WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
pygame.display.update()
mainClock.tick(FPS)

How to fix pygame menu (space invaders)?

This is my first game so excuse the messy code. I am making a space invaders game and everything i implemented is working fine (sprites, function of the game, music, pause screen, etc). I wanted to implement a really simple menu screen where, if you press C, the game starts. However, the problem with this is that no matter where i call the menu function, there is always a problem, here is the code (im just going to post the menu function and main loop since everything else i believe is not needed).
import pygame
import random
import math
from pygame import mixer
# Start pygame
pygame.init()
# Create Screen
screen = pygame.display.set_mode((1000, 710))
# Background Image
background = pygame.image.load('background.png').convert_alpha()
# Menu Variables
menu_font = pygame.font.Font('freesansbold.ttf', 65)
menuX = 380
menuY = 250
# Menu Function
def game_intro(x, y):
menu = True
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
quit()
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
pygame.display.update()
# Game Loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
----game_intro(menuX,menuY)---IF I PUT IT HERE, THE ACTUAL GAME APPEARS FOR ONE SECOND AND IT GOES BACK TO MAIN MENU-----------
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
--------game_intro(menuX,menuY)--- IF I PUT IT HERE, THE GAME APPEARS ONLY WHEN 'c' IS BEING HELD DOWN-----------------
*more code*
# Updating
pygame.display.update()
if i put it above pygame.display.update(), then the same thing happens: the game appears for one second and then it goes back to the menu screen. I have tried to search everywhere but the videos either are from 2014, and the websites with some similar problem don't explain how to fix it. Please help.
First of all you should throw the while loop out of your function.
def game_intro(x, y):
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
the missing code gets put in the mainloop like this
...
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
...
now in your mainloop you need to decide whether to draw the menu or the game
if menu:
game_intro(x, y)
else:
#CODE THAT DRAWS THE GAME
all together:
import pygame
import random
import math
from pygame import mixer
# Start pygame
pygame.init()
# Create Screen
screen = pygame.display.set_mode((1000, 710))
# Background Image
background = pygame.image.load('background.png').convert_alpha()
# Menu Variables
menu_font = pygame.font.Font('freesansbold.ttf', 65)
menuX = 380
menuY = 250
# Menu Function
def game_intro(x, y):
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
# Game Loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
if menu:
game_intro(x, y)
else:
# CODE THAT DRAWS THE GAME
# Updating
pygame.display.update()
this should work
note that you need to set menu to True somewhere to get into the menu

How to draw a continuous line in Pygame?

I want to draw a line when mouse clicked and moving in Pygame framework, it will be a line if I move the mouse very slowly. However, if I move the mouse quickly, it's just incontinuous dots. The question is how to draw a continuous line when mouse move? Thanks in advance.
import pygame, sys
from pygame.locals import *
def main():
pygame.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
mouse_position = (0, 0)
drawing = False
screen = pygame.display.set_mode((600, 800), 0, 32)
screen.fill(WHITE)
pygame.display.set_caption("ScratchBoard")
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
if (drawing):
mouse_position = pygame.mouse.get_pos()
pygame.draw.line(screen, BLACK, mouse_position, mouse_position, 1)
elif event.type == MOUSEBUTTONUP:
mouse_position = (0, 0)
drawing = False
elif event.type == MOUSEBUTTONDOWN:
drawing = True
pygame.display.update()
if __name__ == "__main__":
main()
By calling pygame.draw.line with the same argument (mouse_position) twice, you're not drawing a line, you're drawing a single pixel, because start_pos and end_pos are the same.
To get a contiguous line, you need to save the last position and draw a line between it and the next position, like this (changes are the lines with last_pos):
import pygame, sys
from pygame.locals import *
def main():
pygame.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
mouse_position = (0, 0)
drawing = False
screen = pygame.display.set_mode((600, 800), 0, 32)
screen.fill(WHITE)
pygame.display.set_caption("ScratchBoard")
last_pos = None
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
if (drawing):
mouse_position = pygame.mouse.get_pos()
if last_pos is not None:
pygame.draw.line(screen, BLACK, last_pos, mouse_position, 1)
last_pos = mouse_position
elif event.type == MOUSEBUTTONUP:
mouse_position = (0, 0)
drawing = False
elif event.type == MOUSEBUTTONDOWN:
drawing = True
pygame.display.update()
if __name__ == "__main__":
main()
vgel is right, you need to pass the previous position and the current position to pygame.draw.line. You can also calculate the previous position by subtracting the event.rel attribute of the event from the event.pos attribute.
It's also possible get rid of the drawing variable by using the event.buttons attribute. If event.buttons[0] is True then the left mouse button is being pressed.
import pygame
def main():
pygame.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
screen = pygame.display.set_mode((600, 800), 0, 32)
screen.fill(WHITE)
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
elif event.type == pygame.MOUSEMOTION:
if event.buttons[0]: # Left mouse button down.
last = (event.pos[0]-event.rel[0], event.pos[1]-event.rel[1])
pygame.draw.line(screen, BLACK, last, event.pos, 1)
pygame.display.update()
clock.tick(30) # Limit the frame rate to 30 FPS.
if __name__ == "__main__":
main()

How would I go about making clickable text in Pygame? [duplicate]

This question already has an answer here:
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
Closed 2 years ago.
Basically, here is a section of my code in Pygame:
button_text=pygame.font.Font("C:\Windows\Fonts\Another Danger - Demo.otf",35)
textSurface,textRect=text_objects("Start game",button_text)
textRect.center=(105,295)
screen.blit(textSurface,textRect)
This is the text I'd like to turn into a clickable format, so that when someone presses the text, it can run a function, such as running the next thing possible.
Any help would be greatly appreciated.
Thanks.
Get the rect from the surface that font.render returns and use it for collision detection and the blit position.
import sys
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
text_surface = font.render('text button', True, pg.Color('steelblue3'))
# Use this rect for collision detection with the mouse pos.
button_rect = text_surface.get_rect(topleft=(200, 200))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
# Use event.pos or pg.mouse.get_pos().
if button_rect.collidepoint(event.pos):
print('Button pressed.')
screen.fill((40, 60, 70))
screen.blit(text_surface, button_rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
PyGame does not have buttons, so what you can do here is get the mouse cursor position when clicking with pygame.mouse.get_pos(). If the mouse cursor position is inside the text then you know the text was selected.
Here is an example:
import pygame, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1000, 700))
clock = pygame.time.Clock()
tx, ty = 250, 250
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mouse = pygame.mouse.get_pos()
if mouse[0]in range (tx, tx + 130) and mouse[1] in range (ty, ty + 20):
print("You clicked on the text.")
myfont = pygame.font.SysFont("Marlett", 35)
textsurface = myfont.render(("Start game"), True, (230, 230, 230))
screen.blit(textsurface,(tx, ty))
pygame.display.update()
clock.tick(60)
In this example, I used tx and ty for sizes but you can use rect, it's the same thing.

Categories