Table of Contents

PyGame Terminal

This is a version of a common type of starter program I use for many projects.

It requires PyGame.

The basic idea is that there will be a visible representation of an IBM PC VGA terminal, a DEC VT100 style character set, and so forth. It is a common starting program to replicate any of the BSDGAMES such as Robots, Life, Hack, or any program that requires a portable terminal or where access to the console is not superconvenient (ex. when using an IDE).

There are four basic components:

Additionally a small logo can be used, but if you comment out the logo line it still works.

Simpifying the code

The code can be simplified by removing all references to logos and captions, and removing the boilerplate key code for up and down arrows, etc.

Code Commentary

The most overlooked part of such a system is the font metrics. Often it is required to determine only only the width and height but also determine if there is a baseline or an offset for the characters. It is important to know that there is not always an easy way to do this on a font by font basis and sometimes you must use a manual adjustment. In the base code shown here there is a -2 adjustment to font height in setFont(). This may be adjusted to taste by the programmer based on the font and the situation.

Pro tip, you may also wish to blit the text 1 to 5 pixels to the right and down so that it does not touch the window borders.

The best source for old character sets is The Ultimate Oldschool PC Font Pack. I usually use an IBM_PC_VGA_8x16_PLUS TTF font. They're easy to work with in Python, Java, and C++. If you can't use TTF on the web there are woff and other versions available too. The plus means you can use unicode and/or ANSI codes which is often the only way to print IBM PC special characters. Perfect for those writing a ZZT clone!

The clacon2 font is also very good: http://webdraft.hu/fonts/classic-console/

main.py

from Window import Window
from Game import Game

def main():
    window = Window()
    window.setLogo("logo32x32.png")
    window.setCaption("Basic Console Starter Program")
    window.setSize(960, 640)
    window.setFont("PxPlus_IBM_VGA8.ttf", 32) # 32 point font

    game = Game(window)
    game.start()

if __name__ == "__main__":
    main()

game.py

import pygame
import time

class Game:
    def __init__(self, window):
        self.window = window
        self.screen = window.screen
        self.logo = window.logo
        self.font = window.font

        # Clear the screen.
        self.screen.fill((0, 0, 0))

        # Set up game variables
        self.running = True

    def start(self):
        # Main loop
        while self.running == True:
            self.checkEvents()

            self.screen.fill((0, 0, 0))  # Clear the screen.

            self.drawGame()

            pygame.display.flip()  # update the display.
            time.sleep(1 / 60)  # Sleep for 1/FPS, or about 60 fps.

    def drawGame(self):
        self.drawText(0, 2, "it works!", "gray")


    def checkEvents(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False
                return

            if event.type == pygame.KEYDOWN:
                # key down event, process keys.

                if event.key == pygame.K_LEFT:
                    pass
                    
                elif event.key == pygame.K_RIGHT:
                    pass

                elif event.key == pygame.K_UP:
                    pass

                elif event.key == pygame.K_DOWN:
                    pass

                else:
                    pass


    def drawText(self, at_x, at_y, text, color):
        text_surface = self.font.render(text, False, color)
        x = self.window.fontwidth * at_x
        y = self.window.fontheight * at_y
        self.screen.blit(text_surface, (x + 2, y))

window.py

import pygame

class Window:
    def __init__(self):
        pygame.init()

    def setLogo(self, filename):
        self.logo = pygame.image.load(filename)
        pygame.display.set_icon(self.logo)
        return self.logo

    def setCaption(self, cap):
        pygame.display.set_caption(cap)

    def setSize(self, width, height):
        self.width = width
        self.height = height
        self.size = (width, height)
        self.screen = pygame.display.set_mode(self.size)
        return self.screen

    def setFont(self, filename, size):
        pygame.font.init()
        self.font = pygame.font.Font(filename, size)

        font_width, font_height = self.font.size("@")
        self.fontwidth = font_width
        self.fontheight = size - 2

        return self.font

Next

You may wish to continue on to Pygame Terminal II for a more advanced version of this.