I'm making a game that is for teaching people python, so I'm controlling it by assigning variables, calling functions etc. screeps.com is a similar concept, except it's Javascript, and this is Python. The problem I'm having though, is that I have to use a while loop to refresh the screen, but commands given through the shell can't be executed while the while loop is running. For example, I want to be able to input x += 5, and have the player move to the right. So what I need is a way to refresh the screen at the same time as executing shell commands. Also, I'm using Python 3.4. Thanks in advance.
import pygame
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('My game')
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
crashed = False
pImg = pygame.image.load('player.png')
def car(x,y):
gameDisplay.blit(pImg, (x,y))
x = (display_width * 0.45)
y = (display_height * 0.8)
x_change = 0
car_speed = 0
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
gameDisplay.fill(black)
car(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
Why don't you use two threads
1) Thread - Update the display periodically based on inputs
2) Thread - Process inputs and update the shared variables
Threads are the right way to do this. Make sure you import thread at the top.
import thread
consoling = False
def threadedConsole():
global consoling
consoling = True
exec(raw_input(">>> "))
consoling = False
while True:
#Game loop
if not consoling:
thread.start_new_thread(threadedConsole,())
Related
import pygame
def main():
while True:
print(window_size) # works for some reason
print(window_flag) # works for some reason
print(color_flag) # nope python says no
print(current_fps) # python says no
print(previous_fps) # python says no
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
if color_flag:
... # s.o format issue
if __name__ == "__main__":
window_size = (500, 500)
window_flag = pygame.RESIZABLE
# the rejected trio
color_flag = 0
current_fps = 0.0
previous_fps = 0.0
# :(
window = pygame.display.set_mode(window_size, window_flag)
clock = pygame.time.Clock()
main()
When I attempt to print the color_key and subsequent variables I encounter an UnboundLocalError which confuses me, since window_size and window_flag are output without issue. Could someone provide insight into why this is the case?
This question already has answers here:
How to run multiple while loops at a time in Pygame
(1 answer)
Spawning multiple instances of the same object concurrently in python
(1 answer)
Closed 1 year ago.
Below is a working skeleton of my actual code. What I am attempting to do is to obtain the JOYAXISMOTION, event.value, y so that I can use it in different function outside of the loop. I have already defined the variable y.
import time
import sys
import pygame
import subprocess
import random
from pygame.locals import *
pygame.init()
y = 0
def get_percent_change(current, previous):
if current == previous:
return 0
try:
return ((float(current) - float(previous)) /abs(previous)) * 100.0
except ZeroDivisionError:
return float('inf')
def sendCommands():
time.sleep(5)
print('Hello World')
pygame.joystick.init()
joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())]
for joystick in joysticks:
print(joystick.get_name())
game_state = False
run = True
while run:
for event in pygame.event.get():
if event.type == JOYBUTTONDOWN:
print(event)
if game_state == False and event.button == 8:
game_state = True
if event.button == 4:
game_state = False
if event.type == JOYHATMOTION:
if event.value[0] == 1 or event.value[0] == -1:
game_state = False
if event.type == JOYAXISMOTION:
if event.axis == 4:
current = event.value
y = get_percent_change(current, -1.0001)
print(y)
if event.type == JOYDEVICEADDED:
joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())]
for joystick in joysticks:
print(joystick.get_name())
if event.type == JOYDEVICEREMOVED:
joysticks = [pygame.joystick.Joystick(i) for i in range(pygame.joystick.get_count())]
if game_state == True:
sendCommands()
pygame.quit()
sys.exit()
The main problem I am running into is the time.sleep(5) that the sendCommands requires. It is blocking the script while sleeping. I have tried asyncio with no success. Threading is also very confusing to me here. I have also tried the delay logic in the answer provided to a closely related question here but that also blocks the code from running.
Allow me to pick your brain on how:
I can run the script without it being blocked
and how I can access and use the event.value, y outside of the loop
To use y outside of the loop, you could declare it as global but a better alternative is to make a function to get the value. You can implement a timer to execute your subprocess every 5 seconds instead of blocking the entire thread. The following code prints None every 5 seconds for me since I don't have any controllers connected but I think it will work for you.
import time
import sys
import pygame
from pygame.locals import *
pygame.init()
def sendCommands(waitTime, y):
global sendCommandsStart
#count how many seconds have passed since sendCommandsStart
#variable was last updated
if time.time() - sendCommandsStart > waitTime:
sendCommandsStart = time.time() #reset the timer
print(y)#call your subpreocess here
def getJoyStickY(events):
for event in events:
if event.type == JOYAXISMOTION:
if event.axis == 4:
return get_percent_change(current, -1.0001)
return None
pygame.joystick.init()
run = True
sendCommandsStart = time.time() #get the current time - its just a number (time since last epoh)
while run:
allEvents = pygame.event.get()
sendCommands(5, getJoyStickY(allEvents))
pygame.quit()
sys.exit()
i would like to build a stopwatch for my carrera track which i built a little bit bigger.
So I have bought a Raspberry Pi 3 with an additional 7 "touch screen and the individual modules for triggering.
Everything works fine individually.
Now I found a great stopwatch on the net which I also used. Works really great.
In another script, that I've written by myself, the triggering with the gpios works also fantastic.
Now I want to combine both and fail.
Does anyone have an idea or suggested solution where my mistake is?
Here is my code
#!/usr/bin/python
import tkinter as tk
import RPi.GPIO as GPIO
import time
GPIO_TRIGGER_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_TRIGGER_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setwarnings(False)
def update_timeText():
if (state):
global timer
timer[2] += 1
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
timeString = pattern.format(timer[0], timer[1], timer[2])
timeText.configure(text=timeString)
root.after(10, update_timeText)
def start():
global state
state = True
print('Pressed Start')
def stop():
global state
state = False
print('Pressed Stop')
def reset():
global timer
timer = [0, 0, 0]
timeText.configure(text='00:00:00')
print('Pressed Reset')
while GPIO.input(GPIO_TRIGGER_PIN) == True:
if GPIO.input(GPIO_TRIGGER_PIN):
print('CAR DETECTED')
time.sleep(0.1)
state = False
# BULDING TKinter GUI
root = tk.Tk()
root.wm_title('Stopwatch')
timer = [0, 0, 0]
pattern = '{0:02d}:{1:02d}:{2:02d}'
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 150))
timeText.pack()
startButton = tk.Button(root, text='Start', command=start)
startButton.pack()
stopButton = tk.Button(root, text='Stop', command=stop)
stopButton.pack()
resetButton = tk.Button(root, text='Reset', command=reset)
resetButton.pack()
update_timeText()
root.mainloop()
Currently I get the trigger in the console as output "CAR DETECTED". However, I do not get the TKinter panel.
If I remove
while GPIO.input(GPIO_TRIGGER_PIN) == True:
if GPIO.input(GPIO_TRIGGER_PIN):
print('CAR DETECTED')
time.sleep(0.1)
then the display appears and works. Without triggering.
If I put it all down, I get also the panel but it also triggers nothing more.
Any ideas ?
Thanks for help
Not really my area of expertise, but since nobody else answered, I'll give it a shot.
I think you want to use GPIO.add_event_callback()* to add a callback that gets called when an event happens.
# Callback function
def on_trigger(channel_number):
# Just update the flag
global state
state = False
# Set the callback
GPIO.add_event_callback(GPIO_TRIGGER_PIN , callback=on_trigger)
Then, delete the while loop.
*According to the docs, you need the darksidesync library to use this function. Instead of the callback, you could also create a separate thread. Personally, I would prefer the callback.
from threading import Thread
def thread_function(arg):
global state
# Listen for state change
while GPIO.input(GPIO_TRIGGER_PIN) == True:
if GPIO.input(GPIO_TRIGGER_PIN):
# Update var
state = False
print('CAR DETECTED')
time.sleep(0.1)
thread = Thread(target = thread_function)
thread.start()
Hope this helps.
I cannot display the image that is in the same source folder as my project. Also it gives me squiggly lines under (x, y) and it tells me
"Shadows name "x" & "y" from outer scope"
It shows each one for the "x" and "y" so I just put &
Lastly my quit() at the end tells me
"PEP 8: blank line at the end of file"
Completely new to python and pygame
I am not sure what to try
import pygame
pygame.init()
display_Width = 400
display_Height = 400
gameDisplay = pygame.display.set_mode((display_Height, display_Width))
pygame.display.set_caption('Shonen Run Project')
black = (0, 0, 0)
white = (255, 255, 255)
clock = pygame.time.Clock()
crashed = False
heroImg = pygame.image.load('harper.png')
def hero(x, y):
gameDisplay.blit(heroImg, (x, y))
x = (display_Width * 0.45)
y = (display_Height * 0.8)
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
gameDisplay.fill(white)
hero(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
I guess you use a IDE. The image loading of your code seems fine, just note that it does only work if the current working directory is actually the directory your python file and your image file is in. A simple way to ensure this is:
import os
import sys
os.chdir(sys.path[0])
The other issues are just warnings.
You have two global variables x and y, and a function def hero(x, y): which has also two arguments x and y. The warning tells you that if you access x or y inside hero, you actually access the local x or y and you have no way to access the global x or y (they are shadowed).
I would suggest renaming the global x and y variables to a more meaningful name, and also remove the hero function, since it is pretty useless.
PEP 8 is the python style guide. You should follow it, as it helps to keep your code readable, especially if other people than yourself are going to read your code. But of course it's not a law, and a missing blank line at the end of file will probably bother no one...
i am creating a program for my little brother on pygame where numbers 1-20 will come up in order and each number will be pronounced by mp3 files which i have already created.what i am stuck on now is how to make it so that the sound being played for each number will change as the next button is pressed. i didn't want do it one by one as it will take too long. is there a way to make like a list of all the mp3 sounds together so that the sounds played matches the number showing on the screen.
Sorry it was a long question. This is my first time asking a question and i couldn't find a way to shorten it.
If I understand you correctly, you just need to put the sounds into a list and use the number as the index.
import pygame as pg
pg.init()
SOUNDS = [
pg.mixer.Sound('1.mp3'),
pg.mixer.Sound('2.mp3'),
pg.mixer.Sound('3.mp3'),
]
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
number = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
# Just use the number as the index.
SOUNDS[number].play()
# Increment the number and keep it in the range.
number += 1
number %= len(SOUND_LIST)
screen.fill((30, 30, 30))
print(number)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()