Below is a small piece of my program. Currently, the program takes the user's input and converts it into a binary number in the Python Shell. I am trying to use that input so that I can graphically display the binary number. At the moment, I am unable to get anything to appear in the pygame screen. It is just white, no circles, no text. I am not sure why it is not working. I was advised by my teacher to turn this piece of code into a procedure, see if I have any luck, then get back to him. I was hoping somebody could pick out what is wrong with my procedure and either point it out to me or correct it. Any help would be much appreciated. I apologize if my formatting for the question is not spectacular, this is my first post.
from pygame import*
font.init()
comicFont=font.SysFont("ComicSansMS",12)
screen = display.set_mode((500,500))
binaryWord = str(100101)
binaryDigits = len(binaryWord)
binaryBlit = range(0,10)
binaryGraphicX = 0
color = (0,0,0)
color2 = (125,125,125)
pos = (binaryGraphicX,200)
radius = 15
width = 0
while True:
for binaryDigit in range (0,binaryDigits):
TxtPic = []
binaryGraphicX = binaryGraphicX + 25
if binaryWord[binaryDigit] == 1:
running=True
while running:
for evnt in event.get():
if evnt.type==QUIT:
running = False
event.get()
draw.circle(screen,color,pos,radius)
display.flip()
TxtPic[binaryDigit]=comicFont.render(str(2**binaryBlit),True,(0,0,0))
screen.blit(TxtPic[binaryDigit],(binaryGraphicX,220))
elif binaryWord[binaryDigit] == 0:
running=True
while running:
for evnt in event.get():
if evnt.type==QUIT:
running = False
event.get()
draw.circle(screen,color2,pos,radius)
display.flip()
TxtPic[binaryDigit]=comicFont.render(str(2**binaryBlit),True,(0,0,0))
screen.blit(TxtPic[binaryDigit],(binaryGraphicX,220))
quit()
Below is where I call on the procedure
running=True
while running:
for evnt in event.get():
if evnt.type==QUIT:
running = False
event.get()
screen.fill((255,255,255))
TxtPic1=comicFont.render(str(solution),True,(255,255,255))
screen.blit(TxtPic1,(200,200))
binaryGraphics(binaryNumber)
display.flip()
display.quit()
I have been looking through your code and the first obvious problem I found was that you are comparing a character/string to an int in your if statements.
ie.
String:
binaryWord = str(100101)
String to Int comparison: (would return false and skip)
if binaryWord[binaryDigit] == 1:
Try this instead:
if binaryWord[binaryDigit] == "1":
Your program never has a chance to get to your code that draws text/circles.
Related
I'm trying to build a Wordle clone, a word game where one gets 6 chances to guess a 5 letter word. The game itself works but when I try to show the definition of the word at the end of the game, my whole game gets stuck.
My code is this:
import pygame
import pygame.display
import sys
import random
from words import *
from PyDictionary import PyDictionary
pygame.init()
# a py file with list of words
CORRECT_WORD = WORDS
CORRECT_WORD_LIST = list(CORRECT_WORD)
word = random.choice(CORRECT_WORD_LIST)
# number of attempts, 6 in total
attempts = 0
# a list to store the previous guesses
guesses = [[]] * 6
cur_guess = []
cur_guess_str = ""
current_letter_bg_x = 110
game_result = ""
# get the meaning of the word
def get_meaning(word):
dicto = PyDictionary()
meaning = dicto.meaning(word)
if meaning == "":
meaning = "No definition found"
return meaning
meaning = get_meaning(word)
def blit_text(surface, text, pos, font):
"""Multi-line text blit from https://stackoverflow.com/a/42015712/2280890"""
def check_guess(guess):
# Check if letter is Green, Yellow or grey if not in word
# trimmed, for not being part of the problem
attempts += 1
cur_guess = []
cur_guess_str = ""
current_letter_bg_x = 110
def play_again():
SCREEN.blit(BACKGROUND, BG_RECT)
play_again_text = play_again_font.render("ENTER to Play Again? or Q to Quit!", True, "#FCFCFC")
pygame.display.update()
word_text = play_again_font.render(f"{word.upper()}", True, "#FFB90F")
SCREEN.blit(play_again_text, play_again_rect)
SCREEN.blit(word_text, word_rect)
pygame.display.flip()
def reset():
# Reset all global variables
I've trimmed/removed a bunch of lines relating to creating/drawing letters and backspace etc.
Up until this point everything works as expected. The letters, if in correct position get colored as expected.
My problem starts here. Instead of only showing the definition after 6 attempts it shows the meaning as soon as the game starts. This is the block of code that breaks the game:
for i in enumerate(guesses[attempts]):
if i == 6 and game_result is not "W":
word = random.choice(CORRECT_WORD_LIST)
meaning = get_meaning(word)
txt = f"{meaning}"
txt_pos = (40, 70)
window.blit(BACKGROUND, [-317, -300])
f"{blit_text(window, txt, txt_pos, sys_font)}", True, "#FFB90F"
pygame.display.update
If I omit that block the game runs as expected and if I leave as below, it works as expected.
Game
while running:
if game_result != "":
play_again()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
if game_result != "":
reset()
else:
if len(cur_guess_str) == 5 and cur_guess_str.lower() in WORDS:
check_guess(cur_guess)
elif event.key == pygame.K_BACKSPACE:
if len(cur_guess_str) > 0:
delete_letter()
else:
key_pressed = event.unicode.upper()
if key_pressed in "QWERTYUIOPASDFGHJKLZXCVBNM" and key_pressed != "":
if len(cur_guess_str) < 5:
new_letter()
Can someone help me understand why my logic/reasoning is flawed?
The block of code that is causing issues I insert it right after ### game, in between while running: and right before
if game_result != "":
play_again()
while True:
meaning = ""
for i in range(len(guesses[attempts])):
if i == 6 and game_result is not "W":
word = random.choice(CORRECT_WORD_LIST)
meaning = get_meaning(word)
txt = f"{meaning}"
txt_pos = (40, 70)
window.blit(BACKGROUND, [-317, -300])
f"{blit_text(window, txt, txt_pos, sys_font)}", True, "#FFB90F"
pygame.display.update()
for the code above you have put while running but you never change running so wouldn`t it be better to do while True. Also if you put while True a better way of ending the game is to just do break instead of pygame.quit() and sys.exit(). Also can I see the output that prints when the game breaks please?
Don't Work (I have edited the code and it prints because as soon as the game starts to run you have put txt=f"{meaning}" by moving it across that only happens when i == 6 and game_result is not "W". I don't know if this will work but its worth a try.)
If that doesn`t work from what I can see you don't use enumerate so I would replace it with range(len(guesses[attempts]))
This question already has answers here:
.write not working in Python
(5 answers)
Closed 11 months ago.
So the level and the players score is saved in a textfile but now in order to rewrite the data so that when it loads again it is saved where the player is i use this code
#Exit button
for event in pygame.event.get():
if event.type == pygame.QUIT:
Game_data = open('Gamedata.txt','w')
Game_data.write(level)
Game_data.write(str(Score))
Game_data.close
game_over = True
But now the texfile data just gets removed and stays empty
#Load in text file data
Game_data = open('Gamedata.txt','r')
level = Game_data.readline().split("\n")
Score = Game_data.readline().split("\n")
lives = Game_data.readline().split("\n")
this is the code to read the data
It looks like you have an issue with your string parsing, or perhaps not closing the file. I've created a minimal example that demonstrates loading and saving your game data to a file. Some minor event handling to change the values saved.
import pygame
def load_game_data():
"Load save data, minimal error checking"
try:
with open("game_data.txt", "r") as save_file:
level = save_file.readline().strip() # remove newline
score = int(save_file.readline())
lives = int(save_file.readline())
return level, score, lives
except FileNotFoundError: # no save file, return defaults
return "First", 0, 0
def save_game_data(level, score, lives):
"Save game data, no error checking"
with open("game_data.txt", "w") as save_file:
save_file.write(f"{level}\n")
save_file.write(f"{score}\n")
save_file.write(f"{lives}\n")
WIDTH = 640
HEIGHT = 480
FPS = 30
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
level, score, lives = load_game_data()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYUP:
score += 1
elif event.type == pygame.MOUSEBUTTONUP:
lives += 1
# draw surface - fill background
window.fill(pygame.color.Color("grey"))
# update window title to show score
pygame.display.set_caption(f"Level: {level:10} Lives: {lives:5} Score: {score:5}")
# show surface
pygame.display.update()
# limit frames
clock.tick(FPS)
# frames += 1
pygame.quit()
save_game_data(level, score, lives)
I think format strings are clearer and more explicit. The only thing that tripped me up was stripping the newline when reading the level. The int() function ignores trailing newlines/spaces.
Maybe because you are not closing the file? you are not using the close method close()
Also as a general better practice you should use:
with open('Gamedata.txt','r') as file:
file.write(level)
file.write(str(Score))
Turns out I missed the () by the .close and then i had to add the \n for the new line and it fixed the problem
Game_data = open('Gamedata.txt','w')
Game_data.write(f"{level}\n")
Game_data.write(str(f"{Score}\n"))
Game_data.write(str(f"{lives}\n"))
Game_data.close()
I am writing a short program to display cards in a round. I suspect that it is the length of the code which prevents the final 'OK' submit on P3 (the last player's submission) from executing properly: at which point the program sometimes will evaluate the winner and clear the round, but most of the time instead will freeze.
I have tried clock.tick(low fps), pygame.event.pump(), and pygame.event.clear(). Any leads would be much appreciated.
# Round loop begins. Finish until all hands are empty.
while not self.game.get_is_last_round():
player = self.game.get_player(self.game.get_player_turn())
hand = player.order_hand(player.get_hand(),
self.game.get_round_level(),
self.game.get_round_trump_suit())
ok_clicked_2 = False
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.deal_running = False
self.is_running = False
pygame.display.quit()
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
play = player.get_play()
click = pygame.mouse.get_pressed(num_buttons=3)
pos = pygame.mouse.get_pos()
# Used DeMorgan's law to resolve error
ok_clicked_2 = (OK1_X < pos[0] < OK1_X + B_W) and (OK1_Y < pos[1] < OK1_Y + B_H) and click[0]
b1, card = self.check_hand(pos, player)
b2, play_card = self.check_play(pos, player)
if b1:
hand.remove(card)
play.append(card)
player.set_play(
player.order_hand(play, self.game.get_round_level(),
self.game.get_round_trump_suit()))
player.set_hand(
player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
if b2:
play.remove(play_card)
hand.append(play_card)
player.set_play(
player.order_hand(play, self.game.get_round_level(),
self.game.get_round_trump_suit()))
player.set_hand(player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
clock.tick(100)
surface.blit(background, (0, 0))
if len(self.game.get_player(0).get_hand()) == 25:
self.game.set_is_first_round(True)
else:
self.game.set_is_first_round(False)
if len(self.game.get_player(0).get_hand()) == 0:
self.game.set_is_last_round(True)
else:
self.game.set_is_last_round(False)
if self.game.get_play_in_turn() != NUM_PLAYERS:
pygame.event.pump()
clock.tick(100)
if len(hand) <= 1:
width = 0
x = (BG_WIDTH - CARD_WIDTH) // 2
elif len(hand) >= 8:
width = (BG_WIDTH - SIDE_W - CARD_WIDTH) // (len(hand) - 1)
x = BG_WIDTH // 2 - (CARD_WIDTH + (width * (len(hand) - 1))) // 2
else:
width = CARD_WIDTH
x = (BG_WIDTH - (CARD_WIDTH * len(hand))) // 2
surface.blit(background, (0, 0))
self.blit_backs()
self.blit_round()
self.show_ok()
self.show_hand(x, ROW3h, width, hand)
self.show_hand(CARD_POSITIONS[0][0], CARD_POSITIONS[0][1], SLIM_WIDTH, play)
if ok_clicked_2:
for card in play:
hand.append(card)
player.set_hand(player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
# If player is first to start a round, he/she has a different validity check.
# (Sets the pattern for the cycle)
if player.get_begins_cycle():
valid = self.game.check_validity(True) # is_first
else:
valid = self.game.check_validity(False) # Is not first to play in the round
if not valid: # Clear holding if invalid
if (play == []) or (player.get_play() == []):
print("\nYou must make a play.\n")
else:
print("Invalid play. Try again.")
if not player.get_begins_cycle():
valid_plays = player.get_valid_plays(self.game.get_pattern(),
self.game.get_round_trump_suit())
print("Valid plays: \n")
for temp_play_idx in range(len(valid_plays)):
temp_play = valid_plays[temp_play_idx]
print("[", end='')
for temp_card_idx in range(len(temp_play)):
valid_plays[temp_play_idx][temp_card_idx].show_card("", '')
if temp_card_idx != len(temp_play) - 1:
print(", ", end='')
print("]")
# Clear the current player's selection and restore hand to its original content
cycle_order = self.game.get_cycle_order()
cycle = self.game.get_cycle()
for player_order in range(len(cycle_order)):
if player == cycle_order[player_order]:
cycle_order.remove(player)
cycle.pop()
self.game.set_cycle_order(cycle_order)
self.game.set_cycle(cycle)
else: # Valid play on submit
# Special case for HIGH_SUIT play, play lowest card if another player has greater
play = self.game.check_high_suit(play)
# If friend card played, establish and print teammates
# TODO: auto-designate friends if the last round
# has been reached (friends buried in treasure case)
# TODO: determine whether friend is "dead"
self.game.check_for_friends()
cycle = self.game.get_cycle()
cycle.append(play)
self.game.set_cycle(cycle)
cycle_order = self.game.get_cycle_order()
cycle_order.append(player)
self.game.set_cycle_order(cycle_order)
# self.clear_positions()
for card in play:
hand.remove(card)
player.set_hand(
player.order_hand(hand, self.game.get_round_level(),
self.game.get_round_trump_suit()))
self.game.next_player_turn()
self.game.set_play_in_turn(self.game.get_play_in_turn() + 1)
print(self.game.get_play_in_turn())
play = []
else:
self.game.set_play_in_turn(0)
# Distribute any points in the round to round winner
self.update_cycle_points()
for p in self.game.get_players():
for card in p.get_play():
discard = self.game.get_discard()
discard.append(card)
p.set_play([])
pygame.event.clear()
clock.tick(100)
pygame.display.update()
I think it's time for a code-cleanup, then your issue will go away (or you'll find it).
Currently the main loop is a big mix-up of event handling, screen-painting and game engine. Try to separate these parts out.
Move some of the in-loop processing out to functions - like the block after if ok_clicked_2:. It may help to make a data structure in which you store the game-state, then have the events change that game state. When it comes time to draw the game to the screen, the painting code can query the state, acting accordingly.
In terms of your actual lockup, if self.game.get_play_in_turn() == NUM_PLAYERS nothing is painted to the screen. Is this intentional? Add some print()s to your code so you can know the execution flow (or learn to use the python debugger).
I think the biggest step forward would be to move all the screen painting to one section of the main loop, something like:
# Render the screen
print( "Rendering Screen" )
surface.blit(background, (0, 0))
self.blit_backs()
self.blit_round()
# etc. for all other things, score, buttons, ...
clock.tick(60)
pygame.display.update()
You seem to be handling the events OK, so it would probably be better to remove the calls to pygame.event.pump() and pygame.event.clear(). You don't need these.
Following Kingsley's advice, I organized the code by function: rendering screen, game engine, and event handling. I would provide MRE as Random Davis suggests, but that would include 5 integrated files which would take too long to pare down.
It turns out that the problem lay in a piece of code which is called separately: "update_cycle_points()". Within, there is a while loop which does not contain an event handler. The solution was to change it to a for loop, which Pygame seems to process without error (does not freeze because it does not expect event handling there).
I also removed pygame.event.clear() and pump() functions without problems.
I am trying to recreate Pong in pygame and have tried to change the color of the net to red or green, based on who scores. I am able to keep it red or green after someone scores, until a different person scores, however, I want to change the net color back to black after 3 seconds. I tried using time.sleep(3) but whenever I did it, the net will stay as black. `
elif pong.hitedge_right:
game_net.color = (255,0,0)
time.sleep(3)
scoreboard.sc1 +=1
print(scoreboard.sc1)
pong.centerx = int(screensize[0] * 0.5)
pong.centery = int(screensize[1] * 0.5)
scoreboard.text = scoreboard.font.render('{0} {1}'.formatscoreboard.sc1,scoreboard.sc2), True, (255, 255, 255))
pong.direction = [random.choice(directions),random.choice(directions2)]
pong.speedx = 2
pong.speedy = 3
pong.hitedge_right = False
running+=1
game_net.color=(0,0,0)
Ideally, it should turn red for 3 seconds, then update the scoreboard and restart the ball, however, instead, the entire thing pauses and it skips straight to changing the net color to black. I believe there is a better way of doing this, or maybe I am using time.sleep totally wrong, but I have no idea how to fix this.
You can't use sleep() in PyGame (or any GUI framework) because it stops mainloop which updates other elements.
You have to remember current time in variable and later in loop compare it with current time to see if 3 seconds left. Or you have to create own EVENT which will be fired after 3 second - and you have to check this event in for event.
It may need more changes in code so I can show only how it can look like
Using time/ticks
# create before mainloop with default value
update_later = None
elif pong.hitedge_right:
game_net.color = (255,0,0)
update_later = pygame.time.get_ticks() + 3000 # 3000ms = 3s
# somewhere in loop
if update_later is not None and pygame.time.get_ticks() >= update_later:
# turn it off
update_later = None
scoreboard.sc1 +=1
print(scoreboard.sc1)
# ... rest ...
Using events
# create before mainloop with default value
UPDATE_LATER = pygame.USEREVENT + 1
elif pong.hitedge_right:
game_net.color = (255,0,0)
pygame.time.set_timer(UPDATE_LATER, 3000) # 3000ms = 3s
# inside `for `event` loop
if event.type == UPDATE_LATER:
# turn it off
pygame.time.set_timer(UPDATE_LATER, 0)
scoreboard.sc1 +=1
print(scoreboard.sc1)
# ... rest ...
I am currently working on a game where I wish to give the player an option of four characters to play. Here is my current code to do this:
running = 1
charactersChoice = ['char.png', 'char2.png', 'char3.png', 'char4.png']
choice = ''
while choice == '':
screen.fill((47, 79, 79))
screen.blit(pygame.image.load(charactersChoice[0]), (100,100))
screen.blit(pygame.image.load(charactersChoice[1]), (700,100))
screen.blit(pygame.image.load(charactersChoice[2]), (100,600))
screen.blit(pygame.image.load(charactersChoice[3]), (700,600))
keys = pygame.key.get_pressed()
#Choose character
if keys[pygame.K_1]:
choice = charactersChoice[0]
if keys[pygame.K_2]:
choice = charactersChoice[1]
if keys[pygame.K_3]:
choice = charactersChoice[2]
if keys[pygame.K_4]:
choice = charactersChoice[3]
pygame.display.flip()
while running == 1:
#rest of code for game here
As you can see, I blit the four different character profiles onto the screen and then check if the player has pressed the keys 1-4 to select their option. After selecting their option, it should move onto the main loop. Currently, if I press the key '1' while the code is running, it will not change the variable choice to what is intended.
Hope I have explained my problem well enough.
You have to call pygame.event.pump() at least once before using pygame.key.get_pressed() so that pygame can check what keys have been pressed.