Metadata-Version: 2.1
Name: pygstuff
Version: 0.0.2
Summary: PYGame Stuff for writing pygame applications
Home-page: https://github.com/sustainablelab/pygstuff
Author: Mike Gazes
Author-email: sustainablelab@gmail.com
License: MIT
Platform: Windows
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Development Status :: 1 - Planning
Classifier: Intended Audience :: Developers
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: User Interfaces
Classifier: Topic :: Software Development :: Libraries :: pygame
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: pygame

`pygstuff` is a Python package to simplify developing with pygame.

Install:

```bash
$ pip install pygstuff
```

Import `pygstuff` as `pygs` (pronounced "pigs"):

```python
>>> import pygstuff as pygs
```

# `pygstuff` is a pygame wrapper under development
`pygame` is a great low-level tool for interactive applications.
Low-level means lots of freedom, but lots of boiler-plate code.

`pygstuff` makes pygame applications a little bit higher-level. It is
where my pygame code goes when I get tired of repeating it.

I am **very actively** adding to `pygstuff`. Check for changes:

- if cloned, do `git remote update`
- or if installed, update to the latest with `pip install --upgrade pygstuff`

# Platform compatibility
Developed on Windows using Python3.8 and `pygame 1.9.6`.

# Installation

```bash
$ pip install pygstuff
```

This installs the `wheel` ([built
distribution](https://packaging.python.org/glossary/#term-built-distribution)).

`pygstuff` requires `pygame`. If `pygame` is not installed, `pip
install pygstuff` takes care of installing `pygame` as well.

See [AltInstallallation.md](AltInstallation.md) for developer installation
('--editable') or simply editing PYTHONPATH (no installation).

# Quick example script using `pygstuff`

This example opens a window and draws a line. Quit by pressing
`q` or by clicking on the usual Window close button to quit.

```python
#!python.exe
# -*- coding: utf-8 -*-
'''Draw a line with pygame.'''
import pygame
import pygstuff as pygs

if __name__ == '__main__':
    rgb = pygs.RGB()
    win = pygs.Window()
    win.open_window(1200,600)
    print(f"Display window size: {win.width}x{win.height}")
    clock = pygs.Clock(framerate=50)

    '''game loop'''
    quit = False
    while not quit:
        clock.tick()

        '''--- EVENTS ---'''
        for event in pygame.event.get():
            kp = pygame.key.get_pressed()
            km = pygame.key.get_mods()
            quit = pygs.user.quit(event, kp, km)

        '''--- UPDATE SCREEN ---'''
        win.surface.fill(rgb.blackestgravel)
        pygame.draw.aalines(
            win.surface,
            rgb.dress,
            False, # if True, connect first and last points
            [(100,100), (200,200), (200,300), (500,300)]
            )

        # Flip to new surface drawing
        pygame.display.flip()
```

# Libraries

## pkg window: Class Window

Wraps `pygame.display.set_mode()`, pulling several pygame calls
into two methods: `__init__` and `open`.

The application only makes one instance of Window. This Window
singleton holds:

- the top-level **`pygame` surface** (for drawing everything on)
- the *width* and *height* of the main game window

### Usage for Window

Instantiate a Window:

```python
win = pygs.Window()
```

- initializes pygame
- sets window properties:
    - location
    - caption
    - icon

Open the Window:

```python
win.open()
```

- sets the window size `win.width` and `win.height`
- opens the main game window `win.surface` for drawing to
- the window closes when the application ends
    - this is just pygame's out-of-the-box behavior for closing
      the game window

## pkg clock: Class Clock

This is a very simple wrapper around `pygame.time.Clock()`. All
it does is avoid repeating the framerate value.

### Usage for Clock
Set the framerate when Clock() is instantiated:

```python
clock = pygs.Clock(framerate=60)
```

Then in the game loop, tick the `clock`:

```python
clock.tick()
```

## pkg colors
Color is a distraction when I first start development on
an application. I want nice contrast that is also easy on my eyes
and is good enough if I never bother changing it.

This library gives me Steve Losh's Badwolf scheme in RGB and HEX
format. This is my default scheme for Vim, so it is a natural
default scheme for my applications. It is just what I am used to
looking at. I encourage Vim users to do something similar with
their favorite color schemes.

### Usage for colors namedtuple RGB
Pygame uses RGB. Instantiate an `rgb` version of the Badwolf
palette:

```python
rgb = pygs.RGB()
```

Use one of the gravels as a background:

```python
win.surface.fill(rgb.blackestgravel)
```

Draw a tardis-colored plot (reminds me of the C64 blue):

```python
pygame.draw.aalines(
    win.surface,
    rgb.tardis,
    False, # if True, connect first and last points
    meaningful_data # XY plot data [(x0,y0), ... (xn,yn)]
    )
```

The Badwolf scheme is a small set of colors with easy-to-remember
names:

- the gravels:
    - wide range of brownish-greys from almost white to almost
      black
    - good for background fills and background line work of
      varying emphasis: grid lines, box borders, text
    - e.g., if the background is `blackestgravel`, then:
        - a non-interactive text title is just `gravel`
        - interactive text is `darkgravel` to indicate disabled
          or out-of-focus
        - text is `brightgravel` or a highlight color to indicate
          it is in-focus or it it just became active
- highlight colors:
    - tardis, taffy, saltwatertaffy, dalespale, orange, lime,
      dress
    - I usually have two or three of these in an application,
      e.g.:
    - a tardis command line
    - a saltwatertaffy plot

And, of course, there is simple black and white.

Black (0, 0, 0) is `coal`:

```python
rgb.coal
```

White (255, 255, 255) is `snow`:

```python
rgb.snow
```

## pkg plot

`plot` handles:

- reading data from file
- scaling the data values for fitting the plot on screen

Either the application generates 2d data to plot, or there is a
file with 2d data. Either way, there are x and y values for
plotting.

- x values are stored as a list of floating point values
- y values are stored as a list of floating point values

Right now it's up to the application to flip the data as needed,
dealing with the pygame convention that y=0 is the top line of
the window and y increases moving towards the bottom of the
window.

Like `user`, `plot` is a work in progress. Right now, `plot` is
only handling conversions from the native data to the window
pixel values, scaling data to fit in the plot-window size and
rounding values to integers.

Eventually `plot` will include commands for drawing the plot,
managing multiple plot lines, changing plot styles (colors,
line-thickness, dot-size, line on/off, dot on/off), and typical
user interaction such as changing the plot axes and zooming.

## pkg user

Pygame user interaction is detected via key-presses and events.
Library `user` is a collection of functions that check for common
user interactions and return a Boolean.

### About pygame events, key presses, and key modifications
Typical pygame applications check for user interaction on each
iteration of the game loop:

```python
for event in pygame.event.get():
    kp = pygame.key.get_pressed()
    km = pygame.key.get_mods()
```

This stores user interaction in three variables:

- events
- key presses (like a letter or a number)
- key modifications (like shift or control)

Every function in `pygs.user` takes all three of these variables. I
pass all three to simplify the interface. I don't want to bother
thinking about out which ones to pass.

### typical example: quit
For example, every application needs a way for the user to quit.
The game loop loops until `quit` is True, and every iteration
checks if the user quit. The value of `quit` is updated by
calling `pygs.user.quit()`:

```python
quit = pygs.user.quit(event, kp, km)
```

In this case, all three variables are actually used:

- clicking the Window's red X is an event
- ctrl-q is a keyboard shortcut requiring `kp` for detecting `q` and `km` for detecting if `ctrl` was held down

### More about pygame events
Events are the catch-all for everything else:

- some events are defined by pygame, such as JOYBUTTONDOWN and
  JOYAXISMOTION
- events are also defined by the developer, e.g., a text-entry
  object might trigger an event when the user presses enter or
  when the users selects text with the mouse

## Future packages

### Future goals for pkg user
There is a lot of boilerplate in detecting specific key-presses
and events.

The `user` library is my attempt to simplify this with a
higher-level view asking "what did the user do?" in the form of
functions that return either True or False.

There are many high-level views. This library just represents the
stuff I find most useful.

I intent to redo this library to enable:

- customization in the application code
- use of user-specific keyboard shortcuts, like a `.rc` file

As of now, the library is a mixture of high-level user
interaction, such as pygs.user.quit(), and low-level interaction
such as checking for specific key presses. I use these when the
interpretation of user-intent is application specific. For
example, this returns True if the user presses capital x:

```python
pygs.user.pressed_X(event, key_pressed, key_mods)
```


### new pkg lines

The `pygame` line drawing interfaces specifies line segments with
a start x,y and a stop x,y.

I'm working on a `lines` library that provides a higher-level
interface for working with lines:

- `line`:
    - specify a point (x,y) the line passes through
    - specify the slope

The library converts lines to the visible line segment that fills
the game window.

Building on this `line` interface, `lines` provides a `Tiles`
class.

Instantiate `Tiles` to generate a grid of parallelograms that
tile a portion of the game window. This started out of a need to
draw grids for axonometric (isometric) projection. With the right
parameter values, this simplifies to a rectangular grid for
plotting 2d data.


