User Tools

Site Tools


pygame_framework

PyGame Framework

This is a lighter version of pygame terminal, without the terminal stuff, mainly used for quickly making a 2d arcade style game. We will quickly go over the main points and then discuss changes and patterns discovered over the past several projects.

Fonts

main.py

from Window import *
from Game import *

def main():
    window = Window()
    window.setSize(800,600)
    window.setCaption("PyGame Framework Example")
    window.setFont("clacon2.ttf", 32)

    game = Game(window)
    game.start()

if __name__ == "__main__":
    main()

Window.py

Note that the window will not usually appear until the events loop (“for event in pygame.event.get()”) later.

drawText is included here, since it is a kind of convenience function. If you don't need this you don't need the setFont() in main() or the TTF file either.

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

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

Screen.py

New addition. One of the things we discovered is the need for a “class Constants” or “Globals” sometimes, and screen related things like FPS are kept here. This is required sometimes by sprites to calculate their updates.


class Screen:

    WIDTH = 800
    HEIGHT = 600
    FPS = 60

    MARGIN = 96
    GAMETOP = MARGIN
    GAMEBOT = HEIGHT - MARGIN

Here, margin and gametop are used as display boundaries for things like sprites so text can be drawn at the top of the screen and things stay within the edges of the screen. The most important parts are WIDTH and HEIGHT. A big question is, should Screen and Window be merged?

Game.py

A number of changes. One, instead of display.flip() we use display.update(). Second, instead of time.sleep(1 / 60) to get 60 FPS we use clock.tick(60).

Some extra framework code was added for convenience, mainly the key event stuff. However, please note that the pygame window will not usually appear until the “for event in pygame.event.get()” loop.

import pygame
import time
from Screen import *

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

        # Set up game variables (see notes)
        self.running = True

    def start(self):

        # Clock for controlling the frame rate
        clock = pygame.time.Clock()

        # Variables to keep track of time, if needed
        frame_counter = 0
        time_start = time.time() * 1000

        # Main Loop
        while self.running == True:
            # Manage time for timed events like animations
            time_clock = (time.time() * 1000) - time_start
            frame_counter += 1
            if frame_counter > Screen.FPS:
                frame_counter = 1

            # All event handling
            self.checkEvents()

            # Frame generation
            self.screen.fill((0, 0, 0))  # Clear the screen.
            self.drawGame()
            pygame.display.update()  # update the display. Can also use flip()

            # Control the frame rate
            clock.tick(Screen.FPS)

    def drawGame(self):
        self.window.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_q:
                    self.quit_game()
                if event.key == pygame.K_ESCAPE:
                    self.quit_game()

                if event.key == pygame.K_LEFT:
                    print("left")

                elif event.key == pygame.K_RIGHT:
                    print("right")

                elif event.key == pygame.K_UP:
                    print("up")

                elif event.key == pygame.K_DOWN:
                    print("down")

                else:
                    pass

    def quit_game(self):
        print("Exiting game...")
        pygame.quit()
        quit()
        exit()

Color.py

This is an important file because it allows us to set and use standard colors.

class Color:
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)
    GRAY = (127, 127, 127)

    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE = (0, 0, 255)

    # VGA Colors (in hexadecimal)
    VGA_BLACK = 0x000000  # Color 0
    VGA_BLUE = 0x0000AA  # Color 1
    VGA_GREEN = 0x00AA00  # Color 2
    VGA_CYAN = 0x00AAAA  # Color 3
    VGA_RED = 0xAA0000  # Color 4
    VGA_MAGENTA = 0xAA00AA  # Color 5
    VGA_BROWN = 0xAA5500  # Color 6
    VGA_LIGHT_GRAY = 0xAAAAAA  # Color 7
    VGA_DARK_GRAY = 0x555555  # Color 8
    VGA_LIGHT_BLUE = 0x5555FF  # Color 9
    VGA_LIGHT_GREEN = 0x55FF55  # Color 10
    VGA_LIGHT_CYAN = 0x55FFFF  # Color 11
    VGA_LIGHT_RED = 0xFF5555  # Color 12
    VGA_LIGHT_MAGENTA = 0xFF55FF  # Color 13
    VGA_YELLOW = 0xFFFF55  # Color 14
    VGA_WHITE = 0xFFFFFF  # Color 15

    # Array of VGA colors for easy access by index
    vga_color = [
        VGA_BLACK,  # 0
        VGA_BLUE,  # 1
        VGA_GREEN,  # 2
        VGA_CYAN,  # 3
        VGA_RED,  # 4
        VGA_MAGENTA,  # 5
        VGA_BROWN,  # 6
        VGA_LIGHT_GRAY,  # 7
        VGA_DARK_GRAY,  # 8
        VGA_LIGHT_BLUE,  # 9
        VGA_LIGHT_GREEN,  # 10 (A)
        VGA_LIGHT_CYAN,  # 11 (B)
        VGA_LIGHT_RED,  # 12 (C)
        VGA_LIGHT_MAGENTA,  # 13 (D)
        VGA_YELLOW,  # 14 (E)
        VGA_WHITE  # 15 (F)
    ]

Sound.py

If you need it, and you have sound files, you can do something like this:

import pygame as a

class Sound:
    def __init__(self):
        a.mixer.init()
        dir = 'assets/sound/'
        self.sounds = {}

        #self.sounds["laser"] = a.mixer.Sound(dir+'laser1.wav')
        #self.sounds["laser"].set_volume(0.15)
        #self.sounds["boom"] = a.mixer.Sound(dir+'boom6.wav')
        #self.sounds["boom7"] = a.mixer.Sound(dir+'boom7.wav')
        #self.sounds["start"] = a.mixer.Sound(dir+'start4.wav')
        #self.sounds["pellet"] = a.mixer.Sound(dir+'pellet.wav')

    def play(self, sound):
        if sound in self.sounds:
            self.sounds[sound].play()
        else:
            print(f"There is no {sound} sound!")

Sprite Objects

If you need it, you can try this:

A basic square

import pygame
import time
from Color import *
from Screen import *

# Define the Player Sprite class
class Player(pygame.sprite.Sprite):
    SPEED = 5
    SIZE = 20
    COLOR = Color.WHITE

    def __init__(self):
        super().__init__()

        # Create a surface for the Player
        self.image = pygame.Surface((self.SIZE, self.SIZE))

        # Fill the surface with a color
        self.image.fill(self.COLOR)

        # Get the rectangle for positioning
        self.rect = self.image.get_rect()

        # Set the initial position
        self.rect.center = (Screen.WIDTH // 2, Screen.HEIGHT // 2)

    def update(self):
        # Restrict positioning to screen.
        if self.rect.x < 0:
            self.rect.x = 0
        if self.rect.x > Screen.WIDTH - self.SIZE:
            self.rect.x = Screen.WIDTH - self.SIZE
        if self.rect.y < 0:
            self.rect.y = 0
        if self.rect.y > Screen.HEIGHT - self.SIZE:
            self.rect.y = Screen.HEIGHT - self.SIZE

        # Easier to read, but, slower.
        #self.rect.x = max(0, min(self.rect.x, Screen.WIDTH - self.SIZE))
        #self.rect.y = max(0, min(self.rect.y, Screen.HEIGHT - self.SIZE))
pygame_framework.txt · Last modified: 2024/09/22 05:38 by appledog

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki