I am fairly new to Python and am trying to make a "List the States" game (in which the player has to input the name of the 50 states in the US). However, I wanted to add a countdown to stop the game if you ran out of time. The problem is that I can't get the countdown to update while the "screen.textinput" box is open.
I have tried using multiprocessing and threading modules to run 2 simultaneous while loops. With the first, it opens two separate windows and with the latter, I found info online that it doesn't work with the turtle module.
This my code at the moment:
timer = turtle.Turtle()
timer.penup()
timer.ht()
timer.goto(-300, 250)
game_is_on = True
while game_is_on:
# Update the timer
screen.update()
end = time.time()
timer.clear()
timer.write(f"{int(300 - (end - start))}")
# Input state name and analyze input
right_answers = len(previous_answers)
if right_answers == 0:
answer_state = screen.textinput(title=f"Guess the State", prompt="What's another state's name?").title()
else:
answer_state = screen.textinput(title=f"{right_answers}/50 States Correct",
prompt="What's another state's name?").title()
if answer_state in data.state.to_list() and answer_state not in previous_answers:
name = Names(answer_state, data)
previous_answers.append(answer_state)
if right_answers == 50:
game_is_on = False
if answer_state == "end":
game_is_on = False
Any ideas how to make this work? Perhaps there is a simpler way out that I am not seeing?
Related
i'm using the methode when_motion from the gpiozero library to listen on 3 motion sensor.
for what i understand, this methode permit to callback a fonction when motion is detected while the rest of the programme is running
i'm trying to modify the global variabled i've named state and pickedup to trigger different phase of the programme, to get more control on the overall behaviour.
sensors are triggering sound as expected but the main programme is stuck, never seem to pass the WaitUntil function at the beginning of the main loop
i suspect the state variable not really being global and/or not changing value (but it could be something else
how can i really affect global variable from my method in order for my main programme to go on?
every design suggestion is welcome
here's my code so far:
# a fonction that wait until a condition is fulfill to continue the code
def WaitUntil(condition, output): #defines function
wU = True
while True:
if condition: #checks the condition
output
wU = False
def State(val): #return a global variable without interrupting motion methode
global state
state = val
print("state = {}".format(val))
def Pickedup(val): #return a global variable without interrupting motion methode
global pickedup
pickedup = val
print("pickedup = {}".format(val))
class PIR: # motion sensor object
global state #variables to trigger different phase of the programme
state = 0
global pickedup
pickedup = False
def __init__(self, pin, element):
self.pir = MotionSensor(pin=pin)
self.pir.when_motion = self.motion
self.element = element
self.state = state
self.pickedup = pickedup
def motion(self):
global state
global pickedup
if state == 3: #this is for not playing a sound when you juste put back the object in its jar
self.pir.wait_for_no_motion()
sleep(2)
print("object is back")
State(0)
elif state == 0:
sa.stop_all() #stop alredy playing sound
wave_obj = sa.WaveObject.from_wave_file("{}.wav".format(self.element)) #play the sound associated with this sensor when you pick an object from the associated jar
wave_obj.play()
sleep(5)
print ("objet {} is picked".format(self.element))
Pickedup(True) #wait and consider that the object is picked
WaitUntil(state == 2,FadeOut(0.5)) #wait for programme to reach state 2 and fading out the current playing sound
pir1 = PIR(17,"feu")
pir2 = PIR(27,"eau")
pir3 = PIR(22,"vent")
while True: #from here is the start of the continuous programme
WaitUntil(pickedup == True, print("pick an object")) #here is the problem, cant seem to pass to the next line from here
print("put object in the box")
while cardcount == 0 and pickedup == True:
cards = PN5180().inventory()
cardcount = len(cards)
print(f"{len(cards)} card(s) detected: {' - '.join(cards)}")
#code continue
Problem
My problem consists of me trying to save the position of the player on the board that I created and then loading it when they enter a specified SENTINEL value. Though the problem that I am getting at this current time is referencing something before the assignment.
This is how I think I should be loading the game.
What I've Tried
I've tried defining the values that are said not to be defined or referenced after the assignment earlier, though it ended up still giving me the same error and in the end didn't make sense to me. I've looked up a lot of different problems relating to this but didn't quite get the grasp on it due to terminology and getting to overwhelmed. Hence why I came here to get a straightforward explanation for my exact problem.
Code
Save Game
def SaveGame(player, board):
playerData = {}
playerData['player'] = player
playerData['board'] = board
saveGame = open("Save.p","wb")
pickle.dump(playerData, saveGame)
saveGame.close()
Load Game (where I'm having trouble)
def LoadGame():
player, board = pickle.load(open("Save.p","rb"))
return player, board
Commanding Player (using the save game function)
def CommandPlayer(player,board):
VALID_INPUTS = ["W","A","S","D","Q"]
row = player["row"]
col = player["col"]
while True: # Input validation loop.
userInput = input("Enter a direction (W)(A)(S)(D) to move in or (Q) to quit.): ").upper()
if userInput in VALID_INPUTS:
break
if userInput == "Q":
SaveGame(player, board)
Main.py (where I'm having trouble with the loading)
def Main():
userinput = input("Welcome to the Character Creator 2000, Enter G to generate your Character and stats or Enter (L) to load a Game (0) to Quit: ").upper() #Requests User Input
if userinput == ("L"):
LoadGame()
player, board = CommandPlayer(player, board)
os.system('cls')
ShowBoard(board)
You're not loading the game data back properly. Your SaveGame) function is saving a dictionary, so that is what pickle.load() will return in LoadGame().
Here's the right way of doing it:
def LoadGame():
with open("Save.p", "rb") as pkl_file:
playerData = pickle.load(pkl_file)
player = playerData['player']
board = playerData['board']
return player, board
LoadGame()
player, board = CommandPlayer(player, board)
You have player, board = ... in the wrong place. It should be one line up:
player, board = LoadGame()
CommandPlayer(player, board)
There is module files as well but they work perfectly, the main problem is when you enter a module and it just printing out There is 'none' in here for every module. Additionally, if I wanted to change the fuel gain from 50 to randomly chose between 20,30,40 or 50.
The rest of the code works well but when the npc in a room is outputted it should say there is a 'workers' in here instead of just none for each module.
#Telium - Game
import random
#Global Variables
num_modules = 17 #Number of modules in the space station
module = 1 #Module of space station we are in
last_module = 0 #Last module we were in
possible_moves = [] #List of possible moves we can make
alive = True #Whether player is alive or not
won = False #Whether player has won
power = 100 #Amount of power the space station has
fuel = 500 #Amount of fuel the player has in flamethrower
locked = 0 #Module that has been locked by the player
queen = 0 #Location of queen alien
vent_shafts = [] #Location of ventilation shaft entrances
info_panels = [] #Location of info panels
workers = [] #Location of worker aliens
#procedure declarations
#This loads the global module
def load_module():
global module, possible_moves
possible_moves = get_modules_from(module)
output_module()
def get_modules_from(module):
moves = []
text_file = open("Charles_Darwin\module" + str(module) + ".txt", "r")
for counter in range(0,4):
move_read = text_file.readline()
move_read = int(move_read.strip())
if move_read != 0:
moves.append(move_read)
text_file.close()
return moves
def output_module():
global module
print()
print("--------------------------------------------------------------
-----------------------")
print()
print("You are in module",module)
print()
npc = spawn_npcs()
print("There is a ", npc ,"here")
def output_moves():
global possible_moves
print()
print("From here you can move to modules: | ",end='')
for move in possible_moves:
print(move,'| ',end='')
print()
def get_action():
global module, last_module, possible_moves, power
valid_action = False
while valid_action == False:
print("What do you want to do next ? (MOVE, SCANNER)")
action = input(">")
if action == "MOVE" or action.lower() == 'move' or action.lower()
== 'm' or action.higher() == 'M':
move = int(input("Enter the module to move to: "))
if move in possible_moves:
valid_action = True
last_module = module
module = move
#power is decreased by 1 for every move
power =- 1
else:
print("The module must be connected to the current
module.")
def spawn_npcs():
global num_modules, queen, vent_shaft, greedy_info_panels, workers
module_set = []
for counter in range(2,num_modules):
module_set.append(counter)
random.shuffle(module_set)
i = 0
queen = module_set[i]
for counter in range(0,3):
i=i+1
vent_shafts.append(module_set[i])
for counter in range(0,2):
i=i+1
info_panels.append(module_set[i])
for counter in range(0,3):
i=i+1
workers.append(module_set[i])
def check_vent_shafts():
global num_modules, module, vent_shafts, fuel
if module in vent_shafts:
print("There is a bank of fuel cells here.")
print("You load one into your flamethrower.")
fuel_gained = 50
print("Fuel was",fuel,"now reading:",fuel+fuel_gained)
fuel = fuel + fuel_gained
print("The doors suddenly lock shut.")
print("What is happening to the station?")
print("Our only escape is to climb into the ventilation shaft.")
print("We have no idea where we are going.")
print("We follow the passages and find ourselves sliding down.")
last_module = module
module = random.randint(1,num_modules)
load_module()
#Main Program starts here
#Menu options
print("ENTER 1 for instructions")
print("ENTER 2 to play")
print("ENTER 3 to quit")
menu = int(input("Please enter a number corresponding to what you want to
do: "))
if menu == 1:
instructions = input("Do you want to read the instructions(Y/N): ")
if instructions == "Y":
print("You, the player are trying to navigate around a space
station named the 'Charles Darwin' which contains many modules")
print("The aim of the game is to find a and trap the queen alien
called 'Telium' who is located somewhere randomly in the station, the
queen will try to escape to connectinhg modules so beware")
print("To win - you have to lock the queen in one of the modules
so she is trapped, you can kill her with a flamethrower, there is also
objects to help on the way so keep a look out")
spawn_npcs()
#Outputs where the queen, shafts, panels and workers are located
print("Queen alien is located in module:",queen)
print("Ventilation shafts are located in modules:",vent_shafts)
print("Information panels are located in modules:",info_panels)
print("Worker aliens are located in modules:",workers)
#when the players is alive, the module will load
while alive and not won:
load_module()
if won == False and alive == True:
output_moves()
get_action()
#if power is 0 then the user will die and the game will end
if power == 0:
print("You ran out of life support, you died")
alive == False
#win message once you have trapped the queen or when you run out of life
support
if won == True:
print("The queen is trapped and you burn it to death with your
flamethrower.")
print("Game over. You win!")
if alive == False:
print("The station has run out of power. Unable to sustain life
support, you die.")
check_vent_shafts()
First the easy part. You can randomly get 20, 30, 40 or 50 by using random.randint like this:
random.randint(2, 5) * 10
The harder part:
As you discussed with #Random Davis in the comments, you want to assign the npcs to random modules and then print which one you encounter.
To append three random (possibly repeating) modules, use
for _ in range(0,3):
vent_shafts.append(random.choice(module_set))
Using global variables (and the global keyword) is generally considered bad practice as it can cause sideeffects due to other parts of the program modifying a variable you wouldn't expect it to / forgot about. Try to use them as function parameters where needed and return the results
queen, vent_shafts, info_panels, workers = spawn_npcs(5)
def spawn_npcs(num_modules):
module_set = []
for i in range(2, num_modules):
module_set.append(i)
for _ in range(0,3):
vent_shafts.append(random.choice(module_set))
for _ in range(0,2):
info_panels.append(random.choice(module_set))
for _ in range(0,3):
workers.append(random.choice(module_set))
queen_module = module_set[0]
return queen_module, vent_shafts, info_panels, workers
I'm trying to play background music and the music keeps on starting. I tried to use music.busy, but I can't figure it out. I want it to check if sound/music is playing, then I want it to print "music is playing". If a sound/music isn't playing I want it to start up a new song and loop it.
def musica():
if pygame.mixer.music.get_busy() == True:
print("music is playing")
if pygame.mixer.music.get_busy() == False:
music.play(loops=-1)
An easy way to play looped sounds is winsound. See the python documentation (https://docs.python.org/3.4/library/winsound.html) and set the parameter 'flags' in PlaySound to winsound.SND_LOOP.
I ended up doing this it is more of a workaround but it works:
m = 0
def musica():
global m
if m == 0:
music.play(loops=-1)
m = 1
if you are looking to play a sound during a specific event in a loop (e.g. opening a menu), it is possible to play sound only once by using timers.
example:
sound = pygame.mixer.Sound('sound.wav')
playSound = True
playSound_counter = 0
while:
playSound_counter += 1
if playSound_counter >= 11:
playSound = True
playSound_counter = 0
if i.rect.collidepoint(mouse_position):
if playSound == True :
sound.play()
playSound = False
elif playSound_counter == 10:
playSound_counter = 0
This is essentially two timers - one sets sound back to True every 11 secs, another negates it while mouse is over a rect.
by "playing once" i meant to be able to play it again in a controlled way when a certain event is triggered
I'm writing a basic game where you use the mouse to dodge stars, but I can't get a certain part to work properly.
I'm trying to make it so that after 10 seconds of playing you beat the stage and if you lose, the 10 second timer resets.
Here is what I'm trying:
def time_pass(self):
self.time_passed = time.clock()
print self.time_passed
if self.time_passed > 10:
self.state = 3
This method only runs if self.state == 2 which is the main game, and if self.state == 3 you win, and the losing screen is if self.state == 0. But what happens is I run the game and when I click play it runs self.state 2 and starts the timer, and if I lose the timer keeps going. So then when I go back to the main screen and press play again, it picks up where the timer left off instead of resetting.
If you want to see the full game code:
Star Dodger Git
Thanks in advance.
-ChristianCareaga
Save the time into say start_time when you set self.state = 2.
Change self.time_passed > 10: to if self.time_passed > (start_time + 10):
The game will end 10 after starting.
IOW, don't reset the clock.