user9846722
user9846722

Reputation:

Python = repeat every second

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

Answers (3)

Matthias Fripp
Matthias Fripp

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

gilch
gilch

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

abarnert
abarnert

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

Related Questions