This question already has answers here:
How can I create a text input box with Pygame?
(5 answers)
Closed 2 years ago.
I'm making a program and I'd like to run it using pygame. The key thing is that I need an space for the user to input numbers and at the screen I need to print an array, which may vary in size (always 3 columns, but the user controls the number of lines), but I want it to always been fully shown in the screen. How can I make both things?
You can't expect people to write down code from scratch to accomplish what you want. If it is just advice you need, I can give some.
Pygame has no formal input field or input box introduced. If you want to implement such thing in pygame specifically, you have to keep record of the input keys(keyboard input). And insert the inputs in a string or list, then display them yourself. But you have to implement the methodology of the inputbox you designed, like you should have a condition for backspace where it deletes the last element of the list. Pygame does not do this formally, but you can write something like this.
However, what you need seems like a gui. Which gives a better way of taking inputs, making input fields, giving properties to the program window and the input boxes, making buttons etc.. In this case, if you change your mind, I would suggest Wxpython.
If you want to create a very simple text input box on your own, you could try to define an area with a pygame.Rect, then check if the mouse collides with the rect to select it and use the .unicode attribute of the keyboard events to attach the characters to a list or string which you can display on the screen.
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
your_input_string += event.unicode
There are also some GUI libraries for Pygame like SGC which is pretty easy to use. Alternatives (on pygame.org) are Albow, PGU and OcempGUI (the latter works only with Python 2.7).
This can be done using pygame_gui. Text input is available through a UITextEntryLine instance, while printing an array could be done using a UITextBox. You'll first need to set up the environment as in the quick start guide.
Create a UITextEntryLine instance:
from pygame.rect import Rect
from pygame_gui.elements.ui_text_entry_line import UITextEntryLine
text_input = UITextEntryLine(relative_rect=Rect(0, 0, 100, 100), manager=manager)
Input can be restricted to only numbers using set_allowed_characters:
text_input.set_allowed_characters('numbers')
Adding a check to the event queue allows for getting text input when enter is pressed:
for event in pygame.event.get():
if event.type == pygame.USEREVENT:
if event.user_type == pygame_gui.UI_TEXT_ENTRY_FINISHED:
if event.ui_element == text_input:
entered_text = text
A UITextBox can be set to a custom height by setting the height to -1:
from pygame_gui.elements.ui_text_box import UITextBox
text_box = UITextBox(relative_rect=Rect(0, 0, 100, -1), manager=manager, text='foobar')
Related
I'm making a little game and I want to make another window separately from my main one.
I have the the main game in a main window, and I want to open a new window and do a little animation when the user does something.
In my example code below, when the user presses "a" I want it to open a new window and blit to there.
Here I set up the two windows: (I know this doesnt work, its what I'm asking how to do)
SCREEN_X = 400
SCREEN_Y = 400
BSCREEN_X = 240
BSCREEN_Y = 160
BATTLE_SCENE = pygame.display.set_mode((BSCREEN_X, BSCREEN_Y))
SCREEN = pygame.display.set_mode((SCREEN_X, SCREEN_Y))
and then the program:
def run_ani ():
#Do animation, blitting to BATTLE_SCENE
return
def main_game():
ending=False
while ending==False:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT: ending=True
if event.type == KEYDOWN: # key down or up?
if event.key == K_ESCAPE:
ending=True # Time to leave
print("Stopped Early by user")
elif event.key == K_a:
run_ani()
#Normal screen motion, blitting to SCREEN
if ending: pygame.quit()
return
So far what this does is draws the main screen, then when A is pressed, it stops drawing the main screen animations, but still draws the other animations on the main screen and draws in the top left corner.
I'm pretty sure it does this because I am setting BATTLE_SCENE to be smaller than the main screen, thus when blitting to BATTLE_SCENE it blits to the area I created (240x160) in the top corner of the main screen.
However I want BATTLE_SCENE to be a seperate window, so that when I press 'a' it will pop up, do its thing, then close or at least go behind the main screen.
How to do this? Is it even possible?
Do you really need multiple windows? I mean, do you really need them?
If yes, then you should probably use pyglet/cocos2d instead.
To have multiple windows in pygame, you need multiple processes (one for each window). While this is doable, it's not worth the efford. You'll need IPC to exchange data between the windows, and I guess your code will become error-prone and ugly.
Go with pyglet when you need more than one window.
The better solution is probably to divide your game into scenes. Create multiple scenes so that each one represent one stage of the game, something like MenuScene, MainScene, BattleScene, GameOverScene, OptionScene etc.
Then let each of those scenes handle input/drawing of that very part of the game.
MenuScene handles drawing and input etc. of the game's menu
MainScene handles drawing and input etc. of the running game
BattleScene handles drawing and input etc. of whatever you do in run_ani
In your mainloop, just pass control over to the current scene by implementing the methods draw(), handle_event(), and update().
Some example code to get the idea:
scenes = {'Main': MainScene(),
'Battle': BattleScene()} #etc
scene = scenes['Main']
class MainScene():
...
def handle_event(self, event):
if event.type == KEYUP:
if event.key == K_a:
scene = scenes['Battle']
...
class BattleScene():
...
def draw(self):
# draw your animation
def update(self):
# if animation is over:
scene = scenes['Main']
...
def main_game():
ending=False
While Not ending:
clock.tick(30)
for event in pygame.event.get():
scene.handle_event(event)
scene.update()
scene.draw()
This is an easy way to cleanly seperate the game logic and allow context switching.
======================================Edit=========================================
Actually it won't work. Apperantly pygame only supports one display screen, and when you initialize another, it will close the first. You will stay with two varibles, which in fact are the same surface. You can have instead the game increasing the window size and playing the battle scene on the side of it, to do this, you can call the pygame.display.set_mode() again with different values. The varible which references the display screen will still be usable, as it change its reference to the new one. After the scene is over you can decrease the window back the same way.
==================================================================================
What basically happens is you run a loop, and each iteration of it is rendering and displaying a new frame.
When you call a function inside a loop, it doesn't continue to run until you finish running the function.
One way to solve this problen is just keep calling the function that updates the battle scene in the main loop.
Another way is by using threading. Threading is basically running multiple scripts ("Threads") in the same time.
Luckily, python already implemented this for us with the threading module.
It's too long for me to explain the module here, but you can learn it here. It might be a little complex if you haven't use threads before, but after some time it will be easier.
And If you want to learn more about threading you can go here.
Specificly here, you can have two threads, one for each loop/window, and run them in the same time.
Hope I helped you!
Yes, that is possible. SDL2 is able to open multiple windows. In the example folder you can take a look at "video.py".
https://github.com/pygame/pygame/blob/main/examples/video.py
"This example requires pygame 2 and SDL2. _sdl2 is experimental and will change."
i'm trying to make a simple basic program with pygame. one of the things im trying to make it do is create a randomly sized rectangle somewhere random on the screen in 6 seconds.
i'm very new to all of this, and I am also pretty new to python 2.7(I was learning 3.5 in class)
so far I have:
mob2_spawn = 0
def create_mob():
mob2 = pygame.Rect(random.randint(0,800), random.randint(0,600), random.randint(20,60), random.randint(30,50))
pygame.draw.rect(window_surface, mob_color, mob2)
pygame.display.update()
mob2_spawn = 1
if mob_spawn == 0:
pygame.time.set_timer(25,6000)
mob2_spawn = 1
how do I attach an event ID to something? I understand that the first variable in pygame.time.set_timer is the event id, and should be an integer between 25 and 32. and essentially the timer should run that function associated with that event id every X milliseconds correct
You need to check for an event, for example a button press. First you need to make pygame check for any button presses:
keystate = pygame.key.get_pressed()
Then you need to put this in your code, so that you have an event in your timer:
pygame.time.set_timer(keystate[pygame.K_SPACE], (25, 6000))
That's at least what I think should happen, by the way i'm using the example with the space button.
I hope it works for you!
I am making a game in Pygame and Python, a form of Asteroids. Every 10 seconds, the game should make another asteroid if there isn't more than 10 on the screen at a time. As I was looking over the example code on how to implement it, I saw that I have to use USEREVENT in the code. Could I replace this with a function? For example:
def testfunc():
print "Test"
pygame.time.set_timer(testfunc, 100)
If I can't use the function this way, how would I use the USEREVENT with this code?
Thanks
EDIT: Could the Python Timer object with Pygame instead of using the Pygame set_timer()?
http://docs.python.org/2/library/threading.html#timer-objects
Looking at the documentation, it seems that events are not functions, but numeric IDs representing the type of event. Thus, you want to declare your own event type, something like this:
SPAWNASTEROID = USEREVENT + 1
Then you can queue it up like this:
pygame.time.set_timer(SPAWNASTEROID, 100)
Finally add a handler to main loop, just like for button clicks and whatnot:
elif event.type == SPAWNASTEROID:
if len(asteroids) < 10:
asteroids.append(Asteroid())
EDIT (example code):
Custom event types declared
set_timer
Checking event type
I know that there are already some questions posted regarding the same issue but the solutions proposed didn't help me.
I want to monitor the state of the arrow keys (pressed/not pressed) at any given time so I have the following code:
import pygame
pygame.init()
a=[0,0,0,0]
while True:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
a[0]=1;
else:
a[0]=0;
if keys[pygame.K_RIGHT]:
a[1]=1;
else:
a[1]=0;
if keys[pygame.K_UP]:
a[2]=1;
else:
a[2]=0;
if keys[pygame.K_DOWN]:
a[3]=1;
else:
a[3]=0;
print a
pygame.event.pump()
So, basically, I keep printing a list a of 4 numbers, each representing an arrow key (1 if pressed, 0 otherwise).
However all values of the list are always zero even if i keep pressing the arrow keys for long.
I also tried printing the whole keys array : Turns out all entries are zeros again, no matter which keys I press and for how long
Any help would be greatly appreciated...
Thanks !
EDIT: Forgot to mention that I am using python 2.7 on windows 7
First off, if you haven't actually created a pygame window, no events will be passed to pygame and therefore the result of pygame.key.get_pressed() won't update. Pygame only receives events on the currrent pygame window. You're probably looking at the console, which is not receiving events. I added pygame.display.set_mode((100,100)) just after pygame.init() and then ran the program. I clicked inside the pygame window. Then the console start displaying the appropriate ones in the console.
Also suggest adding something to pause the loop like time.sleep and something like event checking to break out of it. (proper exiting)
I know that this is a vague question, but I was hoping to get some help. I know VBA pretty well, and have been able to accomplish some simple tasks in python as well as the statistical programming language in R.
What I am looking to do is create a simple application that lets me capture data, some of which is captured from the keyboard. Every time there is a keystroke, I wanted to create a new record in my dataset.
For some context, think about creating a simple interface that lets me track the location (and duration) of the puck in an NHL hockey game.
I am not really a programmer, but know just enough to get in trouble and am not really sure where to get started. I simply am looking for some thoughts on a very basic (non-commercial) solution.
Many thanks in advance.
EDIT: I want to capture how long the puck is each zone. I plan on using the directional keys left/right to "follow" the puck from zone to each. Each time the puck changes to a zone, I want to "close" the active record and start a new one. The start and end times will let me calculate how long the puck was in the zone. I also need a way to stop the creation of a new record for things like faceoffs, tv time outs, and end of period. I was planning on using the spacebar. My thought is that if I do this correctly, when I follow along, the times recorded should match up with what is posted on the game clock found on tv. Yes, this is a crazy idea.
If you choose to program in Python:
You could use the pygame package to easily capture keyboard events. The library was built to write games, but would probably give you the functionality that you are looking for with keydown/keyup events. It also handles mouse events and (since it is intended for games) has the ability to do graphics/text. The documentation is really good and it is cross platform. A possible downside is that you have to have a "screen" and it has to have focus. Here is a small example:
import pygame
def main():
"""
Pygame Example
"""
pygame.init()
screen = pygame.display.set_mode((200, 200))
app_running = True
while app_running:
# Get all key/mouse events from system.
events = pygame.event.get()
# Loop thru each event...
for e in events:
# Handle when the program is killed.
if e.type == pygame.QUIT:
app_running = False
break
# Handle key events.
elif e.type == pygame.KEYDOWN:
# Exit if escape is pressed.
if e.key == pygame.K_ESCAPE:
app_running = False
# Do something when the right arrow
# is pressed.
elif e.key == pygame.K_RIGHT:
print "right arrow pressed"
# Do something when the left arrow
# is pressed.
elif e.key == pygame.K_LEFT:
print "left arrow pressed"
# and so on ...
# Fill the screen to blank it.
#screen.fill(mycolor)
# Write someting to the screen to display.
#screen.blit(some_image, some_position)
# Flip to display.
#screen.flip()
pygame.quit()
if __name__ == '__main__':
main()
If you are using a version of Windows you could use the msvcrt library but the event handling is not as nice as pygame: instead of events, you have to deal with raw keyboard output and it is a little less intuitive. Here is a small code snippet from Robert Gillies on ActiveState:
import msvcrt
def funkeypress():
"""
Waits for the user to press any key including function keys. Returns
the ascii code for the key or the scancode for the function key.
"""
while 1:
if msvcrt.kbhit(): # Key pressed?
a = ord(msvcrt.getch()) # get first byte of keyscan code
if a == 0 or a == 224: # is it a function key?
b = ord(msvcrt.getch()) # get next byte of key scan code
x = a + (b*256) # cook it.
return x # return cooked scancode
else:
return a # else return ascii code
Look at scan() for keyboard input in R. And you didn't ask about mouse input, but consider locator() for that.
Put it a loop if you want the output immediately.
Is it necessary that you program it yourself? There is a free program called jwatcher Designed for scoring animal behavior in ethological studies. It seems like that would be well-suited to your task.