I am trying to make an Undertale like game in python - However I have a problem. When I try to 'blit' an image to the screen it doesn't show. I am 'blitting' a heart and I have rescaled it to an appropriate size in a 3rd party program.
import pygame # Imports Pygame Library
import keyboard # Imports Keyboard Library
# Defining Image Components
undertale_logo_ico = pygame.image.load('Undertale_Logo.ico')
Soul_Heart_Red = pygame.image.load('UndertaleHeart.png')
# Define Key-presses
def movement(key_pressed):
if key_pressed == 'right':
print('Right')
elif key_pressed == 'left':
print('Left')
elif key_pressed == 'up':
print('Up')
elif key_pressed == 'down':
print('Down')
else:
print('Not registered key')
# Execute Key Presses:
keyboard.on_press_key("right arrow", lambda _: movement('right'))
keyboard.on_press_key("left arrow", lambda _: movement('left'))
keyboard.on_press_key("up arrow", lambda _: movement('up'))
keyboard.on_press_key("down arrow", lambda _: movement('down'))
keyboard.on_press_key("d", lambda _: movement('right'))
keyboard.on_press_key("a", lambda _: movement('left'))
keyboard.on_press_key("w", lambda _: movement('up'))
keyboard.on_press_key("s", lambda _: movement('down'))
# Display Window Configuration
# area = screen.get_rect()
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
background_colour = (0, 0, 0)
(width, height) = (300, 200)
pygame.display.set_caption('Game 1')
screen.fill(background_colour)
pygame.display.set_icon(undertale_logo_ico)
pygame.display.flip()
# Drawing Player
screen.blit(Soul_Heart_Red, [0, 0])
# Closing Script
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
The blit() is near the bottom of the code.
You have to update the display after blit:
screen.blit(Soul_Heart_Red, [0, 0])
pygame.display.flip() # <---
You have to update the display after the blit.
screen.blit(Soul_Heart_Red, [0, 0])
pygame.display.update()
Related
I have done research and none of it has helped me. Whenever I run my code, pygame just displays a black screen and I don't know how to fix it.
This is my code:
# importing required librarys
import pygame
import sys
import chess
import math
import os
os.chdir('/Users/stella/Desktop/comp sci NEA/ChessGame/images')
#initialise display
X = 800
Y = 800
scrn = pygame.display.set_mode((X, Y))
pygame.init()
#basic colours
WHITE = (255, 255, 255)
GREY = (128, 128, 128)
YELLOW = (204, 204, 0)
BLUE = (50, 255, 255)
BLACK = (0, 0, 0)
#initialise chess board
b = chess.Board()
#load piece images
pieces = {'p': pygame.image.load('bp.png').convert(),
'n': pygame.image.load('bN.png').convert(),
'b': pygame.image.load('bB.png').convert(),
'r': pygame.image.load('bR.png').convert(),
'q': pygame.image.load('bQ.png').convert(),
'k': pygame.image.load('bK.png').convert(),
'P': pygame.image.load('wp.png').convert(),
'N': pygame.image.load('wK.png').convert(),
'B': pygame.image.load('wB.png').convert(),
'R': pygame.image.load('wR.png').convert(),
'Q': pygame.image.load('wQ.png').convert(),
'K': pygame.image.load('wK.png').convert(),
}
def update(scrn,board):
'''
updates the screen basis the board class
'''
for i in range(64):
piece = board.piece_at(i)
if piece == None:
pass
else:
scrn.blit(pieces[str(piece)],((i%8)*100,700-(i//8)*100))
for i in range(7):
i=i+1
pygame.draw.line(scrn,WHITE,(0,i*100),(800,i*100))
pygame.draw.line(scrn,WHITE,(i*100,0),(i*100,800))
pygame.display.flip()
def main_one_agent(BOARD,agent,agent_color):
'''
for agent vs human game
color is True = White agent
color is False = Black agent
'''
#make background black
scrn.fill(BLACK)
#name window
pygame.display.set_caption('Chess')
#variable to be used later
index_moves = []
status = True
while (status):
#update screen
update(scrn,BOARD)
if BOARD.turn==agent_color:
BOARD.push(agent(BOARD))
scrn.fill(BLACK)
else:
for event in pygame.event.get():
# if event object type is QUIT
# then quitting the pygame
# and program both.
if event.type == pygame.QUIT:
status = False
# if mouse clicked
if event.type == pygame.MOUSEBUTTONDOWN:
#reset previous screen from clicks
scrn.fill(BLACK)
#get position of mouse
pos = pygame.mouse.get_pos()
#find which square was clicked and index of it
square = (math.floor(pos[0]/100),math.floor(pos[1]/100))
index = (7-square[1])*8+(square[0])
# if we have already highlighted moves and are making a move
if index in index_moves:
move = moves[index_moves.index(index)]
#print(BOARD)
#print(move)
BOARD.push(move)
index=None
index_moves = []
# show possible moves
else:
piece = BOARD.piece_at(index)
if piece == None:
pass
else:
all_moves = list(BOARD.legal_moves)
moves = []
for m in all_moves:
if m.from_square == index:
moves.append(m)
t = m.to_square
TX1 = 100*(t%8)
TY1 = 100*(7-t//8)
pygame.draw.rect(scrn,BLUE,pygame.Rect(TX1,TY1,100,100),5)
#print(moves)
index_moves = [a.to_square for a in moves]
# deactivates the pygame library
if BOARD.outcome() != None:
print(BOARD.outcome())
status = False
print(BOARD)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
When I run it, all that is displayed is a black screen. No errors are called.
Some of the answers I found suggested indentation but I don't know where that would be as I am fairly new to coding.
I'm trying to make a Cookie Clicker type game using PyGame, but when I use this bit of code:
def display(thing: pygame.Surface, where: tuple=(0, 0), center=False):
WIN.blit(thing, where if center == False else thing.get_rect(center = (WIN.get_width() // 2, WIN.get_height() // 2)))
def font(font: pygame.font.Font, text: str, colour: tuple=(255, 255, 255)):
return font.render(text, False, colour)
def main():
cookies = 0
cps = 1
clock = pygame.time.Clock()
tim = time.time()
run = True
while run:
clock.tick(FPS)
if time.time() - tim > 1:
tim = time.time()
cookies += cps
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
t = font(CFONT64, f"{cookies} Cookies")
display(t, t.get_rect(center = (WIN.get_width() // 2, WIN.get_height() * .07)))
pygame.display.update()
quitPy()
(not full code)
It'll do this:
and overlap the text when it next updates.
How do I clear the text/change the text?
Everything that is drawn is drawn on the target Surface. The entire scene has to be redrawn in each frame. Therefore, the display must be cleared at the beginning of each frame in the application loop:
while run:
# [...]
# clear display
WIN.fill((0, 0, 0))
# draw scene
display(t, t.get_rect(center = (WIN.get_width() // 2, WIN.get_height() * .07)))
# update disaply
pygame.display.update()
I am trying to make a button in python and I attempted to use the Pygame_widgets library but my functions will not execute
import basic
import pygame as pg
import pygame_widgets as pw
from pygame_widgets.button import Button
def startWindow():
pg.init()
win = pg.display.set_mode((600, 600))
button = Button(
win, 100, 100, 300, 150, text='Hello',
fontSize=50, margin=20,
inactiveColour=(255, 0, 0),
pressedColour=(0, 255, 0), radius=20,
onClick=lambda: basicKit = True
)
run = True
while run:
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
pg.quit()
run = False
quit()
win.fill((255, 255, 255))
button.listen(events)
button.draw()
pg.display.update()
if __name__ == '__main__':
stop = False
print("* Welcome To \"Drum Easy\" V 1.0 *")
startWindow()
while stop == False:
kit = input("\nWhat Kit? \n\nBasic\n ^\n 1\n\n>")
if kit == "1":
basic.Kit()
stop = True
else: print('Invalid Kit')
see now in the button = Button part of the code has multiple options that can run functions but none of them seem to work, they all seem to have invalid syntax
A lambda must have an expression, not a statement (assignment, if,
while, ...). So add = lambda x: x + 1 is a valid lambda. But
lambda: basicKit = True is syntactically incorrect. You can instead
define a function that updates your variable and gives this
function to the Button constructor.
Something like that:
def update_basic_kit():
global basicKit
basicKit = True
button = Button(
win, 100, 100, 300, 150, text='Hello',
fontSize=50, margin=20,
inactiveColour=(255, 0, 0),
pressedColour=(0, 255, 0), radius=20,
onClick=update_basic_kit
)
I am developing a small game for learning purposes. I have created a simple animation for the title screen. Since there is also a function for full screen in the code, I wanted to create a title screen that:
Displayed the animation
Turned into full screen when the key was activated
Continued the animation at the point it was before activating full screen
In order to do this, I resorted to threading. However, this is the first time I tried to do any multi-threading, and I donĀ“t know what did I do wrong. The result is an undetermined error.
The code for the title screen is this:
try:
GameAnimation = threading.Thread(target=GameTitleAnimation, (Window, WindowDimensions, FontDictionary, CurrentVersion))
GameAnimation.start()
except:
print "There was an error while loading the screen. Press one key to exit the program."
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Quit()
if event.type == pygame.KEYDOWN:
if event.key == K_ESCAPE:
Quit()
elif event.key == K_f:
Fullscreen(Window, WindowDimensions)
else:
return
The code for the animation is:
TitleWhite = [255, 255, 255, 0]
Black = BASE_BLACK
TitleLetters = ("R", "O", "G", "U", "E", " ", "H", "U", "N", "T", "E", "R")
Title = FontDictionary["TitleFont"][1].render("ROGUE HUNTER", False, TitleWhite)
TextWidth = Title.get_width()
TextHeight = Title.get_height()
TitleXPosition = (WindowDimensions[0] - TextWidth) / 2
TitleYPosition = (WindowDimensions[1] / 2) - (TextHeight / 2)
for letter in TitleLetters:
if letter == " ":
TitleXPosition += CurrentLetterWidth
else:
while TitleWhite[3] < 100:
TitleWhite[3] += 1
CurrentLetter = FontDictionary["TitleFont"][1].render(letter, False, TitleWhite)
CurrentLetter.set_alpha(TitleWhite[3])
Window.blit(CurrentLetter, (TitleXPosition, TitleYPosition))
time.sleep(0.008)
try:
pygame.display.update()
except Exception:
traceback.print_exception
TitleWhite[3] = 0
CurrentLetterWidth = CurrentLetter.get_width()
TitleXPosition += CurrentLetterWidth
FadeInSurface = pygame.Surface((WindowDimensions[0], WindowDimensions[1]))
FadeInSurface.fill(TitleWhite)
OpacityRounds = 1
while TitleWhite[3] < 100.0:
TitleWhite[3] = 1.1 ** OpacityRounds
FadeInSurface.set_alpha(TitleWhite[3])
Window.blit(FadeInSurface, (0, 0))
OpacityRounds += 1
pygame.display.update()
time.sleep (0.015)
time.sleep(0.7)
TitleXPosition = (WindowDimensions[0] - TextWidth) / 2
Version = FontDictionary["BodyFont"][1].render(CURRENT_VERSION, False, TitleWhite)
VersionHeight = Version.get_height()
VersionWidth = Version.get_width()
VersionXPosition = (WindowDimensions[0] - VersionWidth) / 2
VersionYPosition = TitleYPosition + TextHeight
while True:
pygame.draw.rect(Window, Black, (0, 0, WindowDimensions[0], WindowDimensions[1]), 0)
Window.blit(Title, (TitleXPosition, TitleYPosition))
Window.blit(Version, (VersionXPosition, VersionYPosition))
pygame.display.update()
I'd be very grateful if anyone could help me with this. I am going crazy.
There's no reason to use threading in your code. It will only make your code harder to read, harder to debug and error prone.
Usually you want to have some kind of state in your game that you use to determinate what should happen in a frame. You can find a class based example here.
Another way to handle this, which is a bit similar to your code, is to use coroutines.
Look at your animation code and instead of calling pygame.display.update(), give the control back to the main loop. The main loop will handle events, frame limiting and drawing, then give control back to the coroutine (which keeps track of it's own state).
Here's a simple hacky example:
import pygame
import pygame.freetype
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
def game_state(surf):
rect = pygame.Rect(200, 200, 32, 32)
while True:
events = yield
pressed = pygame.key.get_pressed()
x = 1 if pressed[pygame.K_RIGHT] else -1 if pressed[pygame.K_LEFT] else 0
rect.move_ip(x*5, 0)
pygame.draw.rect(surf, pygame.Color('dodgerblue'), rect)
yield
def title_state(surf):
text = 'Awesome Game'
colors = [[255, 255, 255, 20] for letter in text]
font = pygame.freetype.SysFont(None, 22)
font.origin = True
while True:
for color in colors:
color[3] += 33
if color[3] > 255: color[3] = 0
x = 200
for (letter, c) in zip(text, colors):
bounds = font.get_rect(letter)
font.render_to(surf, (x, 100), letter, c)
x += bounds.width + 1
font.render_to(surf, (180, 150), 'press [space] to start', pygame.Color('grey'))
events = yield
yield
def main():
title = title_state(screen)
game = game_state(screen)
state = title
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_ESCAPE:
return
if e.key == pygame.K_SPACE:
state = game if state == title else title
if e.key == pygame.K_f:
if screen.get_flags() & pygame.FULLSCREEN:
pygame.display.set_mode(size)
else:
pygame.display.set_mode(size, pygame.FULLSCREEN)
screen.fill(pygame.Color('grey12'))
next(state)
state.send(events)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
See how the main loop is clean and simple, and all of the game state is handled in the coroutines. The title screen part of the code does not care about fullscreen or not or how to switch to fullscreen, and the main loop does not care of what the title screen coroutine does. And we don't need threading.
In practice it's not that different from the class based example I linked above, but using coroutines makes it easy to implement the title screen animation.
Basically you have an endless loop, you mutate some state (like the color of a letter), and then say "now draw this!" by just calling yield.
This is a large chunk of code to debug.
I'm not familiar with pygame or python threading, but it seems to me that you need to include some debug lines to determine exactly where the error occurs during your game animation thread (if it's even occuring there at all).
Something like this pattern should help determine the source of the problem:
import logging
logging.info("start animation initialization")
...
logging.info("begin animation loop")
...
logging.info("end animation loop")
https://docs.python.org/2/howto/logging.html
I'm making a basic game where I have a surface and everytime I click on the surface it moves 5 pixels to the right. The program is working just fine without the checkCollide(event) function, but when I put the that condition it doesn't move. What is wrong?
My code until now is this
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300,300))
def checkCollide(event):
k = 0
a,b = event.pos
x = P1[0].get_rect()
if x.collidepoint(a,b):
return True
return False
CP1 = [(150, 150)
,(155, 150)
,(160, 150)
,(165, 150)
,(170, 150)
,(175, 150)
,(180, 150)
,(185, 150)
,(190, 150)]
statp1_1 = 0
WHITE = (255,255,255)
DISPLAYSURF.fill(WHITE)
while True: # the main game loop
P1 = [pygame.image.load('PAzul.png'),CP1[statp1_1],statp1_1]
DISPLAYSURF.blit(P1[0], P1[1])
e = pygame.event.get()
for event in e:
if event.type == MOUSEBUTTONUP:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
statp1_1 +=1
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Thank you
Check your logic in these lines of your function:
x = P1[0][0].get_rect()
if x.collidepoint(a,b):
return True
return False
Your code hinges on this bit:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
So you're never evaluating this piece to be true.
I just realized what was wrong. When I do x = P1[0].get_rect() it creates a surface with topleft at (0,0).
What I needed to do was change the position of the rectangle using x.topleft = P1[1]
I've got some tips for you. First store the rect in the P1 list (it contains only the image and the rect in the following example, but maybe you could also add the statp1_1 index to it). Now we can just move this rect, if the user clicks on it (in the example I set the topleft attribute to the next point). Read the comments for some more tips. One thing you need to fix is to prevent the game from crashing when the statp1_1 index gets too big.
import sys
import pygame
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300, 300))
WHITE = (255, 255, 255)
# Don't load images in your while loop, otherwise they have to
# be loaded again and again from your hard drive.
# Also, convert loaded images to improve the performance.
P1_IMAGE = pygame.image.load('PAzul.png').convert() # or .convert_alpha()
# Look up `list comprehension` if you don't know what this is.
CP1 = [(150+x, 150) for x in range(0, 41, 5)]
statp1_1 = 0
# Now P1 just contains the image and the rect which stores the position.
P1 = [P1_IMAGE, P1_IMAGE.get_rect(topleft=CP1[statp1_1])]
clock = pygame.time.Clock() # Use this clock to limit the frame rate.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONUP:
if P1[1].collidepoint(event.pos):
print('clicked')
statp1_1 += 1
# Set the rect.topleft attribute to CP1[statp1_1].
P1[1].topleft = CP1[statp1_1]
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(P1[0], P1[1]) # Blit image at rect.topleft.
pygame.display.update()
clock.tick(30) # Limit frame rate to 30 fps.