Reputation:
So I am creating just a basic game, where you purchase ballons and every balloon you buy raises the amount of money you have get per second. But I cant seem to work out how to add the money on every second, considering I already have a While loop and you can't have another one
This is my code
###Game###
import time
money=1
money_ps=0
score=0
while True:
time.sleep(1)
money=money+money_ps
while score==0:
inp=input().lower()
if inp=="buy" or inp=="purchase":
print("What would you like to buy")
print("•Red Balloon (£1)")
print("•Blue Balloon (£100)")
print("•Yellow Balloon (£10000)")
print("•Green Balloon (£1000000)")
print("•Pink Balloon (£100000000)")
inp=input().lower()
if inp=="red balloon":
if money >= 1:
money_ps=money_ps+0.1
money=money-1
print("You successfully bought a Red Balloon")
else:
print("You are unable to afford this")
elif inp=="blue balloon":
if money >= 100:
money_ps=money_ps+1
money=money-1
print("You successfully bought a Blue Balloon")
else:
print("You are unable to afford this")
elif inp=="bank":
print("You have £",money)
Any help is greatly appreciated
Upvotes: 0
Views: 343
Reputation: 18645
The other answers have done a good job of introducing you to multithreading and event loops, which will be the right answer if you need to report changes to the user while waiting for input. But in your case, since you're not reporting new money as it is added, you could just wait until you get input, then update the money status. That is, you can update the money status from your main input loop, like this:
import time
money = 1
money_ps = 0
score = 0
last_update_time = int(time.time())
def update_money():
global money, last_update_time
new_time = int(time.time())
money = money + (new_time - last_update_time)
last_update_time = new_time
while score==0:
inp=input().lower()
update_money()
if inp=="buy" or inp=="purchase":
print("What would you like to buy")
print("•Red Balloon (£1)")
print("•Blue Balloon (£100)")
print("•Yellow Balloon (£10000)")
print("•Green Balloon (£1000000)")
print("•Pink Balloon (£100000000)")
inp=input().lower()
update_money()
if inp=="red balloon":
if money >= 1:
money_ps=money_ps+0.1
money=money-1
print("You successfully bought a Red Balloon")
else:
print("You are unable to afford this")
elif inp=="blue balloon":
if money >= 100:
money_ps = money_ps+1
money = money - 1
print("You successfully bought a Blue Balloon")
else:
print("You are unable to afford this")
elif inp=="bank":
print("You have £", money)
Upvotes: 0
Reputation: 11691
There are multiple approaches to writing event loops in games. Threading and asyncio are some of the more advanced approaches you may want to consider.
But the simplest approach is to put all the updates inside your while loop. Import time, and add an if statement inside the main loop that checks if at least one second has passed since the last update. If it has, update your state variable.
Game engines will often have a task loop inside the main loop that has a list of any entity that needs to change over time. It then calls an update() method on each entity. Then each entity will check the clock and decide how much to change based on the current time.
while True:
for entity in entities:
entity.update()
But, your input
calls will block the main loop from running. Consider using tkinter for input instead, since this won't block.
Upvotes: 0
Reputation: 366213
Your problem is that your main loop is blocking on those input
calls. Fortunately, this is really just a special case of the fundamental problem behind GUI applications, 3D games, and network servers, so the solutions are pretty well known. Unfortunately, the solutions can be a bit complicated, or at least require a lot of learning.
One solution is asynchronous I/O. If you read from a non-blocking file (input
just reads from sys.stdin
, which acts like a file, even though it isn't on disk), you can use a loop from selectors
, or something higher-level like asyncio
, to wait, with a timeout, until it's ready, instead of waiting forever. Or you can go below the level of stdin
and loop over waiting (with a timeout) for events from the console or the OS and then put those events together into input. Or you can use a higher-level library like curses
to do that for you.
The other solution requires less rethinking of your code: Let your main thread spend all its time running a loop around input
, and use a background thread that runs a different loop, one which updates your money and then sleeps for a second.
See the threading
docs for details and some examples, but you're probably going to want to work through a more thorough tutorial. Anyway, here's the changes you need to make the money loop run in a thread:
money = 1
money_ps = 0
money_lock = threading.Lock()
def money_loop():
global money
global money_ps
global money_lock
while True:
time.sleep(1)
with money_lock:
money=money+money_ps
money_thread = threading.Thread(target=money_loop, args=())
money_thread.start()
Now, we also have to make sure to use the same Lock
whenever we want to access money
or money_ps
in the main thread:
if inp=="red balloon":
with money_lock:
if money >= 1:
money_ps=money_ps+0.1
money=money-1
print("You successfully bought a Red Balloon")
else:
print("You are unable to afford this")
And that's it; now it will work.
Except for one problem: you need a way to tell the background thread to stop when it's time to quit. If your whole program is just going to quit at the same time, then there's a quick and dirty solution to this: using a daemon thread:
money_thread = threading.Thread(target=money_loop, args=(), daemon=True)
Daemon threads get hard-killed as soon as the main thread exits. If your background threads are, say, rewriting files, this can be dangerous, because you can end up with corrupted files only half-way written. But here, all your background thread does is sleep and modify some variables used by the main thread, which doesn't care about them anymore at quitting time, so it's safe.
Upvotes: 1