gameterm- terminal for pygame games
- gameterm is a minimal package, designed for Stickman's New World. it will have the abilty to return a surface of the terminal in its proper state. more info will come as development continues!
- gameterm can be installed through pip. type pip install gameterm, or however you access pip.
there are two main parts to gameterm, terminal
and shell
. terminal is the base window itself, or part of the window, where the text is actually displayed, and commands are entered. shell is a class bound to a terminal, used to give the terminal some functionality.
gameterm is desinged to work well with python's threading
module, to allow functions like input()
not to block the functionality of your game, or whatever you are doing.
read()
: not implemented. will do nothing.readline()
: read and return a single line. will act as a blocking function, until the user hits return.write(text)
: add the text to the last line. split on newlines.flush()
: do nothing. (implemented for use as a file stream)get_surf()
: build and return apygame.Surface
object, representing the terminal.echo(line)
: add line to the lines in the terminal.draw_cursor()
: check if the cursor should be on or off. if it should be on, make sure it is rendered.addch(char)
: add the character to the end of last line.input(event)
: take the event object. if it is KEYDOWN, add the character to the last line.
Terminal(surface,
fps=60, # run at this FPS if in main thread
bgcolour=BLACK, # (0, 0, 0)
fgcolour=WHITE, # (255, 255, 255)
font=_DEF_FONT, # monospace on *nix, Lucida Console on Windows
font_size=12, # font size (pixels)
terminal_size=(500, 350), # terminal size (pixels)
add_safe=True, # add a safe amount of height to the terminal in proportion to the font size
)
the following is a basic example of terminal's use, without threading.
import sys
import pygame
import terminal
def main():
pygame.init()
display = pygame.display.set_mode((500, 350))
term = terminal.Terminal(display)
sys.stdout = term
sys.stdin = term
# this will block, as term.readline will run until complete
print(input())
# hold the terminal open until enter is pressed
input()
if __name__ == '__main__':
main()
bind()
: set sys.stdout, sys.stdin and sys.stdout to the current terminal.run_cmd(cmd, args)
: run the command, if found, with arguments of args.mainloop(fps)
: run a mainloop constantly, updating terminal, and running commands.disable_help()
: disable the "help" command of the shell.
kill()
: stop the mainloop from running.add_event(event)
: add the event to self, and terminal's queue.command()
: use as a decorator, see commandsthreaded_update()
: use every frame to make sure the cursor is drawn correctly
Shell(terminal, # terminal object to be used
surface, # main display surface
pos=(0, 0), # position (top left) where terminal will be displayed
prompt="", # prompt of the command
command_prefix="" # prefix used when calling command
)
a command is created through the decorator Shell.command
. it can act like any normal function.
a command can have type annotations, defaults, and a docstring, which will be parsed, in order to make a good command parser (through argparse), and run it through that.
for example (from tests/test_shell.py):
@shell.command
def add(num1: "first number", num2: "second number"):
"""
add two numbers.
note: if num1 is divisible by 8, it will say "howdy" instead.
"""
if float(num1) % 8 == 0:
# divisible by 8.
print('howdy')
else:
print(float(num1) + float(num2))
you could now call shell.mainloop()
and it would run as expected.
the output of howdy -h
is below:
the following is the entire example from tests/test_shell.py. It demonstrates use of a shell with threading, allowing you to run the shell at the same time as your game.
"""test the shell module using a thread."""
import sys
import os
import threading
# insert parent directory into PYTHONPATH
sys.path.append(os.path.realpath('..\\gameterm'))
print(sys.path)
import pygame as pg
import terminal
from shell import Shell
def test_shell():
"""create and run shell, using three really stupid commands."""
# initiate pygame, create shell object
pg.init()
display = pg.display.set_mode((500, 350))
shell = Shell(terminal.Terminal(display), display, prompt="> ")
# make sys.stdout, err, and in the terminal
# shell.bind()
# start the thread for handling the shell.
threading.Thread(target=lambda: shell.mainloop(60), daemon=True).start()
clock = pg.time.Clock()
fps = 60
@shell.command
def say_hi(hello: "say hello instead of hi" = False):
"""say hi.
if hello is true, say hello instead.
"""
print('hello' if hello else 'hi')
@shell.command
def add(num1: "first number", num2: "second number"):
"""
add two numbers.
note: if num1 is divisible by 8, it will say "howdy" instead.
"""
if int(num1) % 8 == 0:
# divisible by 8.
print('howdy')
else:
print(float(num1) + float(num2))
@shell.command
def echo():
"""ask user for input, and print it once enter has been pressed."""
print(input())
while True:
for event in pg.event.get():
# add all events
shell.add_event(event)
if event.type == pg.QUIT:
raise SystemExit
shell.threaded_update()
pg.display.update()
clock.tick(fps)
if __name__ == '__main__':
test_shell()
If you wish to contribute, please feel free! Please Fork it, then create a Pull Request!