ggame module
ggame
The simple cross-platform sprite and game platform for Brython Server (Pygame, Tkinter to follow?).
Ggame stands for a couple of things: "good game" (of course!) and also "git game" or "github game" because it is designed to operate with Brython Server in concert with Github as a backend file store.
Ggame is not intended to be a full-featured gaming API, with every bell and whistle. Ggame is designed primarily as a tool for teaching computer programming, recognizing that the ability to create engaging and interactive games is a powerful motivator for many progamming students. Accordingly, any functional or performance enhancements that can be reasonably implemented by the user are left as an exercise.
Functionality Goals
The ggame library is intended to be trivially easy to use. For example:
from ggame import App, ImageAsset, Sprite
# Create a displayed object at 100,100 using an image asset
Sprite(ImageAsset("ggame/bunny.png"), (100,100))
# Create the app, with a 500x500 pixel stage
app = App(500,500)
# Run the app
app.run()
Extensions
The ggame
library has been extended with ggmath for geometry
exploration in a manner reminiscent of Geogebra, and ggrocket
for tools and classes to use with rocket and orbital simulations.
Overview
There are three major components to the ggame
system: Assets, Sprites and the App.
Assets
Asset objects (i.e. ImageAsset
, etc.) typically represent separate files that
are provided by the "art department". These might be background images, user interface
images, or images that represent objects in the game. In addition, SoundAsset
is used to represent sound files (.wav
or .mp3
format) that can be played in the
game.
Ggame also extends the asset concept to include graphics that are generated dynamically at run-time, such as geometrical objects, e.g. rectangles, lines, etc.
Sprites
All of the visual aspects of the game are represented by instances of Sprite
or
subclasses of it.
App
Every ggame application must create a single instance of the App
class (or
a sub-class of it). Creating an instance of the App
class will initiate
creation of a pop-up window on your browser. Executing the app's run
method will
begin the process of refreshing the visual assets on the screen.
Events
No game is complete without a player and players produce events. Your code handles user
input by registering to receive keyboard and mouse events using listenKeyEvent
and
listenMouseEvent
methods.
Execution Environment
Ggame is designed to be executed in a web browser using Brython, Pixi.js and Buzz. The easiest way to do this is by executing from runpython, with source code residing on github.
To use Ggame in your own application, you may create a folder called
ggame
in your project. Within ggame
, copy the ggame.py
, sysdeps.py
and
__init__.py
files from the ggame project.
When using ggame
from within runpython, the Github
ggame
repository is automatically placed on the import search path.
Geometry
When referring to screen coordinates, note that the x-axis of the computer screen is horizontal with the zero position on the left hand side of the screen. The y-axis is vertical with the zero position at the top of the screen.
Increasing positive y-coordinates correspond to the downward direction on the computer screen. Note that this is different from the way you may have learned about x and y coordinates in math class!
"""
# ggame
The simple cross-platform sprite and game platform for Brython Server (Pygame, Tkinter to follow?).
Ggame stands for a couple of things: "good game" (of course!) and also "git game" or "github game"
because it is designed to operate with [Brython Server](http://runpython.com) in concert with
Github as a backend file store.
Ggame is **not** intended to be a full-featured gaming API, with every bell and whistle. Ggame is
designed primarily as a tool for teaching computer programming, recognizing that the ability
to create engaging and interactive games is a powerful motivator for many progamming students.
Accordingly, any functional or performance enhancements that *can* be reasonably implemented
by the user are left as an exercise.
## Functionality Goals
The ggame library is intended to be trivially easy to use. For example:
from ggame import App, ImageAsset, Sprite
# Create a displayed object at 100,100 using an image asset
Sprite(ImageAsset("ggame/bunny.png"), (100,100))
# Create the app, with a 500x500 pixel stage
app = App(500,500)
# Run the app
app.run()
## Extensions
The `ggame` library has been extended with [ggmath](/ggame/ggmath.html) for geometry
exploration in a manner reminiscent of Geogebra, and [ggrocket](/ggame/ggrocket.html)
for tools and classes to use with rocket and orbital simulations.
## Overview
There are three major components to the `ggame` system: Assets, Sprites and the App.
### Assets
Asset objects (i.e. `ggame.ImageAsset`, etc.) typically represent separate files that
are provided by the "art department". These might be background images, user interface
images, or images that represent objects in the game. In addition, `ggame.SoundAsset`
is used to represent sound files (`.wav` or `.mp3` format) that can be played in the
game.
Ggame also extends the asset concept to include graphics that are generated dynamically
at run-time, such as geometrical objects, e.g. rectangles, lines, etc.
### Sprites
All of the visual aspects of the game are represented by instances of `ggame.Sprite` or
subclasses of it.
### App
Every ggame application must create a single instance of the `ggame.App` class (or
a sub-class of it). Creating an instance of the `ggame.App` class will initiate
creation of a pop-up window on your browser. Executing the app's `run` method will
begin the process of refreshing the visual assets on the screen.
### Events
No game is complete without a player and players produce events. Your code handles user
input by registering to receive keyboard and mouse events using `ggame.App.listenKeyEvent` and
`ggame.App.listenMouseEvent` methods.
## Execution Environment
Ggame is designed to be executed in a web browser using [Brython](http://brython.info/),
[Pixi.js](http://www.pixijs.com/) and [Buzz](http://buzz.jaysalvat.com/). The easiest
way to do this is by executing from [runpython](http://runpython.com), with source
code residing on [github](http://github.com).
To use Ggame in your own application, you may create a folder called
`ggame` in your project. Within `ggame`, copy the `ggame.py`, `sysdeps.py` and
`__init__.py` files from the [ggame project](https://github.com/BrythonServer/ggame).
When using `ggame` from within [runpython](http://runpython.com), the Github
`ggame` repository is automatically placed on the import search path.
## Geometry
When referring to screen coordinates, note that the x-axis of the computer screen
is *horizontal* with the zero position on the left hand side of the screen. The
y-axis is *vertical* with the zero position at the **top** of the screen.
Increasing positive y-coordinates correspond to the downward direction on the
computer screen. Note that this is **different** from the way you may have learned
about x and y coordinates in math class!
"""
import math
try:
from ggame.sysdeps import *
except:
from sysdeps import *
class Frame(object):
"""
Frame is a utility class for expressing the idea of a rectangular region.
"""
def __init__(self, x, y, w, h):
"""
Initialization for the `ggame.Frame` objects.
`x` and `y` are coordinates of the upper left hand corner of the frame.
`w` and `h` are the width and height of the frame rectangle.
"""
self.GFX = GFX_Rectangle(x,y,w,h)
"""
`GFX` is a reference to the underlying object provided by the system.
"""
self.x = x
"""
X-coordinate of the upper left hand corner of this `ggame.Frame`.
"""
self.y = y
"""
Y-coordinate of the upper left hand corner of this `ggame.Frame`.
"""
self.w = w
"""
Width of the `ggame.Frame`.
"""
self.h = h
"""
Height of the `ggame.Frame`.
"""
@property
def x(self):
return self.GFX.x
@x.setter
def x(self, value):
self.GFX.x = value
@property
def y(self):
return self.GFX.y
@y.setter
def y(self, value):
self.GFX.y = value
@property
def w(self):
return self.GFX.width
@w.setter
def w(self, value):
self.GFX.width = value
@property
def h(self):
return self.GFX.height
@h.setter
def h(self, value):
self.GFX.height = value
@property
def center(self):
"""
`center` property computes a coordinate pair (tuple) for the
center of the frame.
The `center` property, when set, redefines the `x` and `y` properties
of the frame in order to make the center agree with the coordinates
(tuple) assigned to it.
"""
return (self.x + self.w//2, self.y + self.h//2)
@center.setter
def center(self, value):
c = self.center
self.x += value[0] - c[0]
self.y += value[1] - c[1]
class _Asset(object):
"""
Base class for all game asset objects.
The `ggame.Asset` class is set up to understand the concept
of multiple instances of an asset. This is currently only used for image-based
assets.
"""
def __init__(self):
self.GFXlist = [None,]
"""A list of the underlying system objects used to represent this asset."""
@property
def GFX(self):
"""
`GFX` property represents the underlying system object used to represent
this asset. If this asset is composed of multiple assets, then the **first**
asset is referenced by `GFX`.
"""
return self.GFXlist[0]
@GFX.setter
def GFX(self, value):
self.GFXlist[0] = value
def __len__(self):
return len(self.GFXlist)
def __getitem__(self, key):
return self.GFXlist[key]
def __setitem__(self, key, value):
self.GFXlist[key] = value
def __iter__(self):
class Iter():
def __init__(self, image):
self.obj = image
self.n = len(image.GFXlist)
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i ==self.n:
raise StopIteration
self.i += 1
return self.obj.GFXlist[self.i]
return Iter(self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
class ImageAsset(_Asset):
"""
The `ImageAsset` class connects ggame to a specific image **file**.
"""
def __init__(self, url, frame=None, qty=1, direction='horizontal', margin=0):
"""
All `ggame.ImageAsset` instances must specify a file name or url with
the `url` parameter.
If the desired sprite image exists in only a smaller sub-section of the
original image, then the are can be specified by providing the
`frame` parameter, which must be a valid `ggame.Frame` object.
If image file actually is a *collection* of images, such as a so-called
*sprite sheet*, then the `ImageAsset` class supports defining a list
of images, provided they exist in the original image as a **row**
of evenly spaced images or a **column** of images. To specify this,
provide the `qty` (quantity) of images in the row or column, the
`direction` of the list ('horizontal' or 'vertical' are supported),
and an optional `margin`, if there is a gap between successive
images. When used in this way, the `frame` parameter must define the
area of the **first** image in the collection; all subsequent images
in the list are assumed to be the same size.
"""
super().__init__()
self.url = url
"""
A string that represents the path or url of the original file.
"""
del self.GFXlist[0]
self.width = self.height = 0
self.append(url, frame, qty, direction, margin)
def _subframe(self, texture, frame):
return GFX_Texture(texture, frame.GFX)
def append(self, url, frame=None, qty=1, direction='horizontal', margin=0):
"""
Append a texture asset from a new image file (or url). This method
allows you to build a collection of images into an asset (such as you
might need for an animated sprite), but without using a single
sprite sheet image.
The parameters for the `append` method are identical to those
supplied to the `ggame.ImageAsset` initialization method.
This method allows you to build up an asset that consists of
multiple rows or columns of images in a sprite sheet or sheets.
"""
GFX = GFX_Texture_fromImage(url, False)
dx = 0
dy = 0
for i in range(qty):
if not frame is None:
self.width = frame.w
self.height = frame.h
if direction == 'horizontal':
dx = frame.w + margin
elif direction == 'vertical':
dy = frame.h + margin
f = Frame(frame.x + dx * i, frame.y + dy * i, frame.w, frame.h)
GFX = self._subframe(GFX, f)
else:
self.width = GFX.width
self.height = GFX.height
self.GFXlist.append(GFX)
class Color(object):
"""
The `ggame.Color` class is used to represent colors and/or colors with
transparency.
"""
def __init__(self, color, alpha):
"""
A `ggame.Color` instance must specify both a `color` as an integer
in the conventional format (usually as a hexadecimal literal, e.g.
0xffbb33 that represents the three color components, red, green
and blue), and a transparency value, or `alpha` as a floating
point number in the range of 0.0 to 1.0 where 0.0 represents
completely transparent and 1.0 represents completely solid.
Example: `red = Color(0xff0000, 1.0)`
"""
self.color = color
self.alpha = alpha
def __eq__(self, other):
return type(self) is type(other) and self.color == other.color and self.alpha == other.alpha
black = Color(0, 1.0)
"""
Default black color
"""
white = Color(0xffffff, 1.0)
"""
Default white color
"""
class LineStyle(object):
"""
The `ggame.LineStyle` class is used to represent line style when
drawing geometrical objects such as rectangles, ellipses, etc.
"""
def __init__(self, width, color):
"""
When creating a `ggame.LineStyle` instances you must specify
the `width` of the line in pixels and the `color` as a valid
`ggame.Color` instance.
Example: `line = LineStyle(3, Color(0x00ff00, 1.0))` will define
a 3 pixel wide green line.
"""
self.width = width
self.color = color
def __eq__(self, other):
return type(self) is type(other) and self.width == other.width and self.color == other.color
blackline = LineStyle(1, black)
"""
Default thin black line
"""
whiteline = LineStyle(1, white)
"""
Default thin white line
"""
class _GraphicsAsset(_Asset):
def __init__(self):
super().__init__()
GFX_Graphics.clear()
class _CurveAsset(_GraphicsAsset):
def __init__(self, line):
super().__init__()
GFX_Graphics.lineStyle(line.width, line.color.color, line.color.alpha)
class _ShapeAsset(_CurveAsset):
def __init__(self, line, fill):
super().__init__(line)
GFX_Graphics.beginFill(fill.color, fill.alpha)
class RectangleAsset(_ShapeAsset):
"""
The `ggame.RectangleAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, width, height, line=blackline, fill=black):
"""
Creation of a `ggame.RectangleAsset` requires specification of the
rectangle `width` and `height` in pixels, the `line` (as a proper
`ggame.LineStyle` instance) and fill properties (as a `ggame.Color`
instance).
"""
super().__init__(line, fill)
self.width = width
self.height = height
self.GFX = GFX_Graphics.drawRect(0, 0, self.width, self.height).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
class CircleAsset(_ShapeAsset):
"""
The `ggame.CircleAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, radius, line=blackline, fill=black):
"""
Creation of a `ggame.CircleAsset` requires specification of the circle
`radius` in pixels, the `line` (as a proper `ggame.LineStyle` instance)
and fill properties (as a `ggame.Color` instance).
"""
super().__init__(line, fill)
self.radius = radius
self.GFX = GFX_Graphics.drawCircle(0, 0, self.radius).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
class EllipseAsset(_ShapeAsset):
"""
The `ggame.EllipseAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, halfw, halfh, line=blackline, fill=black):
"""
Creation of a `ggame.EllipseAsset` requires specification of the ellipse
`halfw`, or semi-axis length in the horizontal direction (half of the
ellipse width) and the `halfh`, or semi-axis length in the vertical direction.
`line` (as `ggame.LineStyle` instance) and `fill` (as `ggame.Color` instance)
must also be provided.
"""
super().__init__(line, fill)
self.halfw = halfw
self.halfh = halfh
self.GFX = GFX_Graphics.drawEllipse(0, 0, self.halfw, self.halfh).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
class PolygonAsset(_ShapeAsset):
"""
The `ggame.PolygonAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, path, line=blackline, fill=black):
"""
Creation of a `ggame.PolygonAsset` requires specification of a
`path` consisting of a list of coordinate tuples. `line` and
`fill` arguments (instances of `ggame.LineStyle` and `ggame.Color`,
respectively) must also be supplied. The final coordinate in the
list must be the same as the first.
Example: `poly = PolygonAsset([(0,0), (50,50), (50,100), (0,0)], linesty, fcolor)`
"""
super().__init__(line, fill)
self.path = path
jpath = []
for point in self.path:
jpath.extend(point)
self.GFX = GFX_Graphics.drawPolygon(jpath).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
class LineAsset(_CurveAsset):
"""
The `ggame.LineAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file. A `LineAsset` instance
represents a single line segment.
"""
def __init__(self, x, y, line=blackline):
"""
Creation of a `ggame.LineAsset` requires specification of an `x` and
`y` coordinate for the endpoint of the line. The starting point of the
line is implied as coordinates (0,0). Note that when this asset is
used in a `ggame.Sprite` class, the sprite's `x` and `y` coordinates
will control the location of the line segment on the screen.
As the `ggame.LineAsset` does not cover a region, only a `ggame.LineStyle`
argument must be supplied (`line`).
"""
super().__init__(line)
self.deltaX = x
"""This attribute represents the `x` parameter supplied during instantiation."""
self.deltaY = y
"""This attribute represents the `y` parameter supplied during instantiation."""
GFX_Graphics.moveTo(0, 0)
self.GFX = GFX_Graphics.lineTo(self.deltaX, self.deltaY).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
class TextAsset(_GraphicsAsset):
"""
The `ggame.TextAsset` is a "virtual" asset that is created on the fly
without requiring creation of an image file. A `TextAsset` instance
represents a block of text, together with its styling (font, color, etc.).
"""
def __init__(self, text, **kwargs):
"""
The `ggame.TextAsset` must be created with a string as the `text` parameter.
The remaining optional arguments must be supplied as keyword parameters. These
parameters are described under the class attributes, below:
"""
super().__init__()
self.text = text
self.style = kwargs.get('style', '20px Arial')
"""A string that specifies style, size and typeface (e.g. `'italic 20pt Helvetica'` or `'20px Arial'`)"""
width = kwargs.get('width', 100)
"""Width of the text block on the screen, in pixels."""
self.fill = kwargs.get('fill', Color(0, 1))
"""A valid `ggame.Color` instance that specifies the color and transparency of the text."""
self.align = kwargs.get('align', 'left')
"""The alignment style of the text. One of: `'left'`, `'center'`, or `'right'`."""
self.GFX = GFX_Text(self.text,
{'font': self.style,
'fill' : self.fill.color,
'align' : self.align,
'wordWrap' : True,
'wordWrapWidth' : width,
})
"""The `GFX` property represents the underlying system object."""
self.GFX.alpha = self.fill.alpha
self.GFX.visible = False
def _clone(self):
return type(self)(self.text,
style = self.style,
width = self.width,
fill = self.fill,
align = self.align)
@property
def width(self):
return self.GFX.width
@property
def height(self):
return self.GFX.height
class Sprite(object):
"""
The `ggame.Sprite` class combines the idea of a visual/graphical asset, a
position on the screen, and *behavior*. Although the `ggame.Sprite` can be
used as-is, it is generally subclassed to give it the desired behavior.
When subclassing the `ggame.Sprite` class, you may customize the initialization
code to use a specific asset. A 'step' or 'poll' method may be added
for handling per-frame actions (e.g. checking for collisions). Step or poll
functions are not automatically called by the `ggame.App` class, but you
may subclass the `ggame.App` class in order to do this.
Furthermore, you may wish to define event callback methods in your customized
sprite class. With customized creation, event handling, and periodic processing
you can achieve fully autonomous behavior for your class.
"""
_rectCollision = "rect"
_circCollision = "circ"
def __init__(self, asset, pos=(0,0), edgedef=None):
"""
The `ggame.Sprite` must be created with an existing graphical `asset`.
An optional `pos` or position may be provided, which specifies the
starting (x,y) coordinates of the sprite on the screen. By default,
the position of a sprite defines the location of its upper-left hand
corner. This behavior can be modified by customizing the `center` of
the sprite.
An optional `edgedef` or edge definition may be provided, which
specifies an asset that will be used to define the boundaries of
the sprite for the purpose of collision detection. If no `edgedef`
asset is given, the Sprite asset is used, which will be a rectangular
asset in the case of an image texture. This option is typically used
to define a visible image outline for a texture-based sprite that has
a transparent texture image background.
Example: player = Sprite(ImageAsset("player.png", (100,100), CircleAsset(50))
This creates a sprite using the `player.png` image, positioned with its
upper left corner at coordinates (100,100) and with a 50 pixel radius
circular collision border.
"""
self._index = 0
if type(asset) == ImageAsset:
self.asset = asset
try:
#self.GFX = GFX_Sprite()
self.GFX = GFX_Sprite(asset.GFX) # GFX is PIXI Sprite
except:
self.GFX = None
elif type(asset) in [RectangleAsset,
CircleAsset,
EllipseAsset,
PolygonAsset,
LineAsset,
]:
self.asset = asset
self.GFX = GFX_Sprite(asset.GFX.generateTexture())
#self.GFX = asset.GFX.clone() # GFX is PIXI Graphics (from Sprite)
#self.GFX.visible = True
elif type(asset) in [TextAsset]:
self.asset = asset._clone()
self.GFX = self.asset.GFX # GFX is PIXI Text (from Sprite)
self.GFX.visible = True
if not edgedef:
self.edgedef = asset
else:
self.edgedef = edgedef
self.xmin = self.xmax = self.ymin = self.ymax = 0
self.position = pos
"""Tuple indicates the position of the sprite on the screen."""
self._extentsdirty = True
"""Boolean indicates if extents must be calculated before collision test"""
self._createBaseVertices()
self._setExtents()
"""Initialize the extents (xmax, xmin, etc.) for collision detection"""
App._add(self)
def _createBaseVertices(self):
"""
Create sprite-relative list of vertex coordinates for boundary
"""
self._basevertices = []
assettype = type(self.edgedef)
if assettype in [RectangleAsset, ImageAsset, TextAsset]:
self._basevertices = [(0,0),
(0,self.edgedef.height),
(self.edgedef.width,self.edgedef.height),
(self.edgedef.width,0)]
elif assettype is PolygonAsset:
self._basevertices = self.edgedef.path[:-1]
elif assettype is LineAsset:
self._basevertices = [(0,0),
(self.edgedef.deltaX, self.edgedef.deltaY)]
elif assettype is EllipseAsset:
w = self.edgedef.halfw * 2
h = self.edgedef.halfh * 2
self._basevertices = [(0,0), (0,h), (w,h), (w,0)]
def _xformVertices(self):
"""
Create window-relative list of vertex coordinates for boundary
"""
# find center as sprite-relative points (note sprite may be scaled)
x = self.width * self.fxcenter / self.scale
y = self.height * self.fycenter / self.scale
if self.scale != 1.0:
sc = self.scale
# center-relative, scaled coordinates
crsc = [((xp-x)*sc,(yp-y)*sc) for xp,yp in self._basevertices]
else:
crsc = [(xp-x,yp-y) for xp,yp in self._basevertices]
# absolute, rotated coordinates
c = math.cos(self.rotation)
s = math.sin(self.rotation)
self._absolutevertices = [(self.x + x*c + y*s, self.y + -x*s + y*c)
for x,y in crsc]
def _setExtents(self):
"""
update min/max x and y based on position, center, width, height
"""
if self._extentsdirty:
if type(self.asset) is CircleAsset:
th = math.atan2(
self.fycenter - 0.5, 0.5 - self.fxcenter) + self.rotation
D = self.width
L = math.sqrt(math.pow(self.fxcenter - 0.5, 2) +
math.pow(self.fycenter - 0.5, 2)) * D
self.xmin = self.x + int(L*math.cos(th)) - D//2
self.ymin = self.y - int(L*math.sin(th)) - D//2
self.xmax = self.xmin + D
self.ymax = self.ymin + D
else:
# Build vertex list
self._xformVertices()
x, y = zip(*self._absolutevertices)
self.xmin = min(x)
self.xmax = max(x)
self.ymin = min(y)
self.ymax = max(y)
self._extentsdirty = False
def firstImage(self):
"""
Select and display the *first* image used by this sprite.
"""
self.GFX.texture = self.asset[0]
def lastImage(self):
"""
Select and display the *last* image used by this sprite.
"""
self.GFX.texture = self.asset[-1]
def nextImage(self, wrap = False):
"""
Select and display the *next* image used by this sprite.
If the current image is already the *last* image, then
the image is not advanced.
If the optional `wrap` parameter is set to `True`, then calling
`ggame.Sprite.nextImage` on the last image will cause the *first*
image to be loaded.
"""
self._index += 1
if self._index >= len(self.asset):
if wrap:
self._index = 0
else:
self._index = len(self.asset)-1
self.GFX.texture = self.asset[self._index]
def prevImage(self, wrap = False):
"""
Select and display the *previous* image used by this sprite.
If the current image is already the *first* image, then
the image is not changed.
If the optional `wrap` parameter is set to `True`, then calling
`ggame.Sprite.prevImage` on the first image will cause the *last*
image to be loaded.
"""
self._index -= 1
if self._index < 0:
if wrap:
self._index = len(self.asset)-1
else:
self._index = 0
self.GFX.texture = self.asset[self._index]
def setImage(self, index=0):
"""
Select the image to display by giving its `index`, where an index
of zero represents the *first* image in the asset.
This is equivalent to setting the `ggame.Sprite.index` property
directly.
"""
self.index = index
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def circularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
@property
def index(self):
"""This is an integer index in to the list of images available for this sprite."""
return self._index
@index.setter
def index(self, value):
self._index = value
try:
self.GFX.texture = self.asset[self._index]
except:
self._index = 0
self.GFX.texture = self.asset[self._index]
@property
def width(self):
"""
This is an integer representing the display width of the sprite.
Assigning a value to the width will scale the image horizontally.
"""
return self.GFX.width
@width.setter
def width(self, value):
self.GFX.width = value
self._extentsdirty = True
@property
def height(self):
"""
This is an integer representing the display height of the sprite.
Assigning a value to the height will scale the image vertically.
"""
return self.GFX.height
@height.setter
def height(self, value):
self.GFX.height = value
self._extentsdirty = True
@property
def x(self):
"""
This represents the x-coordinate of the sprite on the screen. Assigning
a value to this attribute will move the sprite horizontally.
"""
return self.GFX.position.x
@x.setter
def x(self, value):
deltax = value - self.GFX.position.x
self.xmax += deltax
self.xmin += deltax
"""Adjust extents directly with low overhead"""
self.GFX.position.x = value
@property
def y(self):
"""
This represents the y-coordinate of the sprite on the screen. Assigning
a value to this attribute will move the sprite vertically.
"""
return self.GFX.position.y
@y.setter
def y(self, value):
deltay = value - self.GFX.position.y
self.ymax += deltay
self.ymin += deltay
"""Adjust extents directly with low overhead"""
self.GFX.position.y = value
@property
def position(self):
"""
This represents the (x,y) coordinates of the sprite on the screen. Assigning
a value to this attribute will move the sprite to the new coordinates.
"""
return (self.GFX.position.x, self.GFX.position.y)
@position.setter
def position(self, value):
self.x, self.y = value
@property
def fxcenter(self):
"""
This represents the horizontal position of the sprite "center", as a floating
point number between 0.0 and 1.0. A value of 0.0 means that the x-coordinate
of the sprite refers to its left hand edge. A value of 1.0 refers to its
right hand edge. Any value in between may be specified. Values may be assigned
to this attribute.
"""
try:
return self.GFX.anchor.x
self._extentsdirty = True
except:
return 0.0
@fxcenter.setter
def fxcenter(self, value):
"""
Float: 0-1
"""
try:
self.GFX.anchor.x = value
self._extentsdirty = True
except:
pass
@property
def fycenter(self):
"""
This represents the vertical position of the sprite "center", as a floating
point number between 0.0 and 1.0. A value of 0.0 means that the x-coordinate
of the sprite refers to its top edge. A value of 1.0 refers to its
bottom edge. Any value in between may be specified. Values may be assigned
to this attribute.
"""
try:
return self.GFX.anchor.y
except:
return 0.0
@fycenter.setter
def fycenter(self, value):
"""
Float: 0-1
"""
try:
self.GFX.anchor.y = value
self._extentsdirty = True
except:
pass
@property
def center(self):
"""
This attribute represents the horizontal and vertical position of the
sprite "center" as a tuple of floating point numbers. See the
descriptions for `ggame.Sprite.fxcenter` and `ggame.Sprite.fycenter` for
more details.
"""
try:
return (self.GFX.anchor.x, self.GFX.anchor.y)
except:
return (0.0, 0.0)
@center.setter
def center(self, value):
try:
self.GFX.anchor.x = value[0]
self.GFX.anchor.y = value[1]
self._extentsdirty = True
except:
pass
@property
def visible(self):
"""
This boolean attribute may be used to change the visibility of the sprite. Setting
`ggame.Sprite.visible` to `False` will prevent the sprite from rendering on the
screen.
"""
return self.GFX.visible
@visible.setter
def visible(self, value):
self.GFX.visible = value
@property
def scale(self):
"""
This attribute may be used to change the size of the sprite ('scale' it) on the
screen. Value may be a floating point number. A value of 1.0 means that the sprite
image will keep its original size. A value of 2.0 would double it, etc.
"""
try:
return self.GFX.scale.x
except AttributeError:
return 1.0
@scale.setter
def scale(self, value):
self.GFX.scale.x = value
self.GFX.scale.y = value
self._extentsdirty = True
@property
def rotation(self):
"""
This attribute may be used to change the rotation of the sprite on the screen.
Value may be a floating point number. A value of 0.0 means no rotation. A value
of 1.0 means a rotation of 1 radian in a counter-clockwise direction. One radian
is 180/pi or approximately 57.3 degrees.
"""
try:
return -self.GFX.rotation
except AttributeError:
return 0.0
@rotation.setter
def rotation(self, value):
self.GFX.rotation = -value
if value:
self._extentsdirty = True
@classmethod
def collidingCircleWithPoly(cls, circ, poly):
return True
def collidingPolyWithPoly(self, obj):
return True
def collidingWith(self, obj):
"""
Return a boolean True if this sprite is currently overlapping the sprite
referenced by `obj`. Returns False if checking for collision with
itself. Returns False if extents of object make it impossible for
collision to occur. Returns True if sprite's `edgedef` parameter overlaps
with other sprite's `edgedef` parameter, taking into consideration both
sprites' center, rotation and scale settings.
"""
if self is obj:
return False
else:
self._setExtents()
obj._setExtents()
# Gross check for overlap will usually rule out a collision
if (self.xmin > obj.xmax
or self.xmax < obj.xmin
or self.ymin > obj.ymax
or self.ymax < obj.ymin):
return False
# Otherwise, perform a careful overlap determination
elif type(self.asset) is CircleAsset:
if type(obj.asset) is CircleAsset:
# two circles .. check distance between
sx = (self.xmin + self.xmax) / 2
sy = (self.ymin + self.ymax) / 2
ox = (obj.xmin + obj.xmax) / 2
oy = (obj.ymin + obj.ymax) / 2
d = math.sqrt((sx-ox)**2 + (sy-oy)**2)
return d <= self.width/2 + obj.width/2
else:
return self.collidingCircleWithPoly(self, obj)
else:
if type(obj.asset) is CircleAsset:
return self.collidingCircleWithPoly(obj, self)
else:
return self.collidingPolyWithPoly(obj)
def collidingWithSprites(self, sclass = None):
"""
Return a list of sprite objects identified by the `sclass` parameter
that are currently colliding with (that is, with which the `ggame.Sprite.collidingWith`
method returns True) this sprite. If `sclass` is set to `None` (default), then
all other sprites are checked for collision, otherwise, only sprites whose
class matches `sclass` are checked.
"""
if sclass is None:
slist = App.spritelist
else:
slist = App.getSpritesbyClass(sclass)
return list(filter(self.collidingWith, slist))
def destroy(self):
"""
Call the `ggame.Sprite.destroy` method to prevent the sprite from being displayed,
or checked in collision detection. If you only want to prevent a sprite from being
displayed, set the `ggame.Sprite.visible` attribute to `False`.
"""
App._remove(self)
self.GFX.destroy()
class SoundAsset(object):
"""
Class representing a single sound asset (sound file, such as .mp3 or .wav).
"""
def __init__(self, url):
"""
Create a `ggame.SoundAsset` instance by passing in the URL or file name
of the desired sound. Sound file formats may include `.wav` or `.mp3`, subject
to browser compatibility.
"""
self.url = url
"""
A string containing the url or name of the asset file.
"""
class Sound(object):
"""
The `ggame.Sound` class represents a sound, with methods for controlling
when and how the sound is played in the application.
"""
def __init__(self, asset):
"""
Pass a valid `ggame.SoundAsset` instance when creating a `ggame.Sound` object.
"""
self.asset = asset
"""
A reference to the `ggame.SoundAsset` instance.
"""
self.SND = SND_Sound(self.asset.url)
"""
A reference to the underlying sound object provided by the system.
"""
self.SND.load()
def play(self):
"""
Play the sound once.
"""
self.stop()
self.SND.play()
def loop(self):
"""
Play the sound continuously, looping forever.
"""
self.stop()
self.SND.loop()
self.SND.play()
def stop(self):
"""
Stop playing the sound.
"""
self.SND.stop()
@property
def volume(self):
"""
The `ggame.Sound.volume` property is a number ranging from 0-100, that
represents the volume or intensity of the sound when it is playing.
"""
return self.SND.getVolume()
@volume.setter
def volume(self, value):
self.SND.setVolume(value)
class _Event(object):
def __init__(self, hwevent):
self.hwevent = hwevent
"""The underlying system event object."""
self.type = hwevent.type
"""String representing the type of received event."""
self.consumed = False
"""
Set the `consumed` member of the event to prevent the event
from being received by any more handler methods.
"""
class MouseEvent(_Event):
"""
The `ggame.MouseEvent` class encapsulates information regarding a user mouse
action that is being reported by the system.
"""
mousemove = "mousemove"
"""Constant identifying a `mousemove` event."""
mousedown = "mousedown"
"""Constant identifying a `mousedown` event."""
mouseup = "mouseup"
"""Constant identifying a `mouseup` event."""
click = "click"
"""Constant identifying a button `click` event."""
dblclick = "dblclick"
"""Constant identifying a button `dblclick` event."""
mousewheel = "wheel"
"""Constant identifying a mouse `wheel` scroll event."""
def __init__(self, hwevent):
"""
The event is initialized by the system, with a `hwevent` input parameter.
"""
super().__init__(hwevent)
self.wheelDelta = 0
"""Integer representing up/down motion of the scroll wheel."""
if self.type == self.mousewheel:
self.wheelDelta = hwevent.deltaY
else:
self.wheelDelta = 0
rect = App._win._renderer.view.getBoundingClientRect()
xscale = App._win.width/rect.width
yscale = App._win.height/rect.height
self.x = (hwevent.clientX - rect.left) * xscale
"""The window x-coordinate of the mouse pointer when the event occurred."""
self.y = (hwevent.clientY - rect.top) * yscale
"""The window y-coordinate of the mouse pointer when the event occurred."""
class KeyEvent(_Event):
"""
The `ggame.KeyEvent` class encapsulates information regarding a user keyboard
action that is being reported by the system.
"""
no_location = 0
"""Constant indicating no specific location for the key event."""
right_location = 2
"""Constant indicating the key event was on the right hand side of the keyboard."""
left_location = 1
"""Constant indicating the key event was on the left hand side of the keyboard."""
keydown = "keydown"
"""Constant indicating the key was pressed down."""
keyup = "keyup"
"""Constant indicating the key was released."""
keypress = "keypress"
"""Constant indicating the combination of keydown, followed by keyup."""
keys = {8: 'backspace',
9: 'tab',
13: 'enter',
16: 'shift',
17: 'ctrl',
18: 'alt',
19: 'pause/break',
20: 'caps lock',
27: 'escape',
32: 'space',
33: 'page up',
34: 'page down',
35: 'end',
36: 'home',
37: 'left arrow',
38: 'up arrow',
39: 'right arrow',
40: 'down arrow',
45: 'insert',
46: 'delete',
48: '0',
49: '1',
50: '2',
51: '3',
52: '4',
53: '5',
54: '6',
55: '7',
56: '8',
57: '9',
65: 'a',
66: 'b',
67: 'c',
68: 'd',
69: 'e',
70: 'f',
71: 'g',
72: 'h',
73: 'i',
74: 'j',
75: 'k',
76: 'l',
77: 'm',
78: 'n',
79: 'o',
80: 'p',
81: 'q',
82: 'r',
83: 's',
84: 't',
85: 'u',
86: 'v',
87: 'w',
88: 'x',
89: 'y',
90: 'z',
91: 'left window key',
92: 'right window key',
93: 'select key',
96: 'numpad 0',
97: 'numpad 1',
98: 'numpad 2',
99: 'numpad 3',
100: 'numpad 4',
101: 'numpad 5',
102: 'numpad 6',
103: 'numpad 7',
104: 'numpad 8',
105: 'numpad 9',
106: 'multiply',
107: 'add',
109: 'subtract',
110: 'decimal point',
111: 'divide',
112: 'f1',
113: 'f2',
114: 'f3',
115: 'f4',
116: 'f5',
117: 'f6',
118: 'f7',
119: 'f8',
120: 'f9',
121: 'f10',
122: 'f11',
123: 'f12',
144: 'num lock',
145: 'scroll lock',
186: 'semicolon',
187: 'equal sign',
188: 'comma',
189: 'dash',
190: 'period',
191: 'forward slash',
192: 'grave accent',
219: 'open bracket',
220: 'back slash',
221: 'close bracket',
222: 'single quote'}
"""Dictionary mapping key code integers to textual key description."""
def __init__(self, hwevent):
"""
The event is initialized by the system, with a `hwevent` input parameter.
"""
super().__init__(hwevent)
self.keynum = hwevent.keyCode
"""The `keynum` attribute identifies a keycode (number)."""
self.key = self.keys[hwevent.keyCode]
"""The `key` attribute identifes the key in text form (e.g. 'back slash')."""
class App(object):
"""
The `ggame.App` class is a (typically subclassed) class that encapsulates
handling of the display system, and processing user events. The `ggame.App`
class also manages lists of all `ggame.Sprite` instances in the application.
When subclassing `ggame.App` you may elect to instantiate most of your
sprite objects in the initialization section.
Processing that must occur on a per-frame basis may be included by overriding
the `ggame.App.step` method. This is also an appropriate location to call
similar 'step' methods for your various customized sprite classes.
Once your application class has been instantiated, begin the frame drawing
process by calling its `ggame.App.run` method.
NOTE: Only **one** instance of an `ggame.App` class or subclass may be
instantiated at a time.
"""
spritelist = []
"""List of all sprites currently active in the application."""
_eventdict = {}
_spritesdict = {}
_spritesadded = False
_win = None
def __init__(self, *args):
"""
The `ggame.App` class is called either by specifying the desired app window size
in pixels, as two parameters (e.g. `myapp = App(640,480)`), or by providing
no size parameters at all (e.g. `myapp = App()`), in which case, the full browser
window size is used.
"""
if App._win == None and (len(args) == 0 or len(args) == 2):
x = y = 0
if len(args) == 2:
x = args[0]
y = args[1]
App._win = GFX_Window(x, y, type(self)._destroy)
self.width = App._win.width
self.height = App._win.height
# Add existing sprites to the window
if not App._spritesadded and len(App.spritelist) > 0:
App._spritesadded = True
for sprite in App.spritelist:
App._win.add(sprite.GFX)
App._win.bind(KeyEvent.keydown, self._keyEvent)
App._win.bind(KeyEvent.keyup, self._keyEvent)
App._win.bind(KeyEvent.keypress, self._keyEvent)
App._win.bind(MouseEvent.mousewheel, self._mouseEvent)
App._win.bind(MouseEvent.mousemove, self._mouseEvent)
App._win.bind(MouseEvent.mousedown, self._mouseEvent)
App._win.bind(MouseEvent.mouseup, self._mouseEvent)
App._win.bind(MouseEvent.click, self._mouseEvent)
App._win.bind(MouseEvent.dblclick, self._mouseEvent)
def _routeEvent(self, event, evtlist):
for callback in reversed(evtlist):
if not event.consumed:
callback(event)
def _keyEvent(self, hwevent):
evtlist = App._eventdict.get(
(hwevent.type, KeyEvent.keys.get(hwevent.keyCode,0)), [])
evtlist.extend(App._eventdict.get((hwevent.type, '*'), []))
if len(evtlist) > 0:
evt = KeyEvent(hwevent)
self._routeEvent(evt, evtlist)
return False
def _mouseEvent(self, hwevent):
evtlist = App._eventdict.get(hwevent.type, [])
if len(evtlist) > 0:
evt = MouseEvent(hwevent)
self._routeEvent(evt, evtlist)
return False
@classmethod
def _add(cls, obj):
if App._win != None:
App._win.add(obj.GFX)
App.spritelist.append(obj)
if type(obj) not in App._spritesdict:
App._spritesdict[type(obj)] = []
App._spritesdict[type(obj)].append(obj)
@classmethod
def _remove(cls, obj):
if App._win != None:
App._win.remove(obj.GFX)
App.spritelist.remove(obj)
App._spritesdict[type(obj)].remove(obj)
def _animate(self, dummy):
if self.userfunc:
self.userfunc()
else:
self.step()
App._win.animate(self._animate)
@classmethod
def _destroy(cls, *args):
"""
This will close the display window/tab, remove all references to
sprites and place the `App` class in a state in which a new
application could be instantiated.
"""
if App._win:
App._win.unbind(KeyEvent.keydown)
App._win.unbind(KeyEvent.keyup)
App._win.unbind(KeyEvent.keypress)
App._win.unbind(MouseEvent.mousewheel)
App._win.unbind(MouseEvent.mousemove)
App._win.unbind(MouseEvent.mousedown)
App._win.unbind(MouseEvent.mouseup)
App._win.unbind(MouseEvent.click)
App._win.unbind(MouseEvent.dblclick)
App._win.destroy()
App._win = None
for s in list(App.spritelist):
s.destroy()
App.spritelist = []
App._spritesdict = {}
App._eventdict = {}
App._spritesadded = False
@classmethod
def listenKeyEvent(cls, eventtype, key, callback):
"""
Register to receive keyboard events. The `eventtype` parameter is a
string that indicates what type of key event to receive (value is one
of: `'keydown'`, `'keyup'` or `'keypress'`). The `key` parameter is a
string indicating which key (e.g. `'space'`, `'left arrow'`, etc.) to
receive events for. The `callback` parameter is a reference to a
function or method that will be called with the `ggame.KeyEvent` object
when the event occurs.
See the source for `ggame.KeyEvent.keys` for a list of key names
to use with the `key` paramter.
"""
evtlist = App._eventdict.get((eventtype, key), [])
if not callback in evtlist:
evtlist.append(callback)
App._eventdict[(eventtype, key)] = evtlist
@classmethod
def listenMouseEvent(cls, eventtype, callback):
"""
Register to receive mouse events. The `eventtype` parameter is
a string that indicates what type of mouse event to receive (
value is one of: `'mousemove'`, `'mousedown'`, `'mouseup'`, `'click'`,
`'dblclick'` or `'mousewheel'`). The `callback` parameter is a
reference to a function or method that will be called with the
`ggame.MouseEvent` object when the event occurs.
"""
evtlist = App._eventdict.get(eventtype, [])
if not callback in evtlist:
evtlist.append(callback)
App._eventdict[eventtype] = evtlist
@classmethod
def unlistenKeyEvent(cls, eventtype, key, callback):
"""
Use this method to remove a registration to receive a particular
keyboard event. Arguments must exactly match those used when
registering for the event.
"""
App._eventdict[(eventtype,key)].remove(callback)
@classmethod
def unlistenMouseEvent(cls, eventtype, callback):
"""
Use this method to remove a registration to receive a particular
mouse event. Arguments must exactly match those used when
registering for the event.
"""
App._eventdict[eventtype].remove(callback)
@classmethod
def getSpritesbyClass(cls, sclass):
"""
Returns a list of all active sprites of a given class.
"""
return App._spritesdict.get(sclass, [])
def step(self):
"""
The `ggame.App.step` method is called once per animation frame. Override
this method in your own subclass of `ggame.App` to perform periodic
calculations, such as checking for sprite collisions, or calling
'step' functions in your own customized sprite classes.
The base class `ggame.App.step` method is empty and is intended to be overriden.
"""
pass
def run(self, userfunc = None):
"""
Calling the `ggame.App.run` method begins the animation process whereby the
`ggame.App.step` method is called once per animation frame. Set `userfunc`
to any function which shall be called once per animation frame.
"""
self.userfunc = userfunc
App._win.animate(self._animate)
if __name__ == '__main__':
def test(event):
print("BOOM")
x = input("Enter something")
print(x)
def testm(event):
print('squeek!')
xcenter = 0.0
xstep = 0.01
scale = 0.5
red = Color(0xff0000, 1.0)
blue = Color(0x0000ff, 1.0)
line = LineStyle(0, red)
poly = PolygonAsset([(0,0),(50,75),(100,60),(90,150),(45,100),(0,0)], line, red)
circ = CircleAsset(75, line, red)
circ2 = CircleAsset(55, line, blue)
bun = ImageAsset('bunny.png')
bun.center = (0.5,0.5)
rect = RectangleAsset(30,150)
ell = EllipseAsset(10,3)
spr = Sprite(bun, (200,300))
spr2 = Sprite(poly, (375, 255))
# TRYING to get the extents to initialize!!
spr2._extentsdirty = True
spr2._setExtents()
spr2.rotation = 0.000
# /\ this does it
h1 = Sprite(LineAsset(500,0))
h2 = Sprite(LineAsset(500,0))
v1 = Sprite(LineAsset(0,500))
v2 = Sprite(LineAsset(0,500))
hh1 = Sprite(LineAsset(500,0))
hh2 = Sprite(LineAsset(500,0))
vv1 = Sprite(LineAsset(0,500))
vv2 = Sprite(LineAsset(0,500))
def step():
global spr
global spr2
global xcenter
global xstep
global h1
global h2
global v1
global v2
global hh1
global hh2
global vv1
global vv2
global scale
scale = scale + xstep
spr.fxcenter = xcenter
spr.fycenter = xcenter
xcenter = xcenter + xstep
if xcenter >= 1.0 or xcenter <= 0.0:
xstep = xstep * -1
spr.rotation = spr.rotation + 10*xstep
spr.scale = scale
spr.x += 1
spr._setExtents()
h1.y = spr.ymin
h2.y = spr.ymax
v1.x = spr.xmin
v2.x = spr.xmax
spr2._setExtents()
hh1.y = spr2.ymin
hh2.y = spr2.ymax
vv1.x = spr2.xmin
vv2.x = spr2.xmax
if spr.collidingWith(spr2):
print("BANG")
app = App()
app.listenKeyEvent('keydown', 'e', test)
app.listenMouseEvent('mousedown', testm)
app.run(step)
Module variables
var black
Default black color
var blackline
Default thin black line
var white
Default white color
var whiteline
Default thin white line
Classes
class App
The App
class is a (typically subclassed) class that encapsulates
handling of the display system, and processing user events. The App
class also manages lists of all Sprite
instances in the application.
When subclassing App
you may elect to instantiate most of your
sprite objects in the initialization section.
Processing that must occur on a per-frame basis may be included by overriding
the step
method. This is also an appropriate location to call
similar 'step' methods for your various customized sprite classes.
Once your application class has been instantiated, begin the frame drawing
process by calling its run
method.
NOTE: Only one instance of an App
class or subclass may be
instantiated at a time.
class App(object):
"""
The `ggame.App` class is a (typically subclassed) class that encapsulates
handling of the display system, and processing user events. The `ggame.App`
class also manages lists of all `ggame.Sprite` instances in the application.
When subclassing `ggame.App` you may elect to instantiate most of your
sprite objects in the initialization section.
Processing that must occur on a per-frame basis may be included by overriding
the `ggame.App.step` method. This is also an appropriate location to call
similar 'step' methods for your various customized sprite classes.
Once your application class has been instantiated, begin the frame drawing
process by calling its `ggame.App.run` method.
NOTE: Only **one** instance of an `ggame.App` class or subclass may be
instantiated at a time.
"""
spritelist = []
"""List of all sprites currently active in the application."""
_eventdict = {}
_spritesdict = {}
_spritesadded = False
_win = None
def __init__(self, *args):
"""
The `ggame.App` class is called either by specifying the desired app window size
in pixels, as two parameters (e.g. `myapp = App(640,480)`), or by providing
no size parameters at all (e.g. `myapp = App()`), in which case, the full browser
window size is used.
"""
if App._win == None and (len(args) == 0 or len(args) == 2):
x = y = 0
if len(args) == 2:
x = args[0]
y = args[1]
App._win = GFX_Window(x, y, type(self)._destroy)
self.width = App._win.width
self.height = App._win.height
# Add existing sprites to the window
if not App._spritesadded and len(App.spritelist) > 0:
App._spritesadded = True
for sprite in App.spritelist:
App._win.add(sprite.GFX)
App._win.bind(KeyEvent.keydown, self._keyEvent)
App._win.bind(KeyEvent.keyup, self._keyEvent)
App._win.bind(KeyEvent.keypress, self._keyEvent)
App._win.bind(MouseEvent.mousewheel, self._mouseEvent)
App._win.bind(MouseEvent.mousemove, self._mouseEvent)
App._win.bind(MouseEvent.mousedown, self._mouseEvent)
App._win.bind(MouseEvent.mouseup, self._mouseEvent)
App._win.bind(MouseEvent.click, self._mouseEvent)
App._win.bind(MouseEvent.dblclick, self._mouseEvent)
def _routeEvent(self, event, evtlist):
for callback in reversed(evtlist):
if not event.consumed:
callback(event)
def _keyEvent(self, hwevent):
evtlist = App._eventdict.get(
(hwevent.type, KeyEvent.keys.get(hwevent.keyCode,0)), [])
evtlist.extend(App._eventdict.get((hwevent.type, '*'), []))
if len(evtlist) > 0:
evt = KeyEvent(hwevent)
self._routeEvent(evt, evtlist)
return False
def _mouseEvent(self, hwevent):
evtlist = App._eventdict.get(hwevent.type, [])
if len(evtlist) > 0:
evt = MouseEvent(hwevent)
self._routeEvent(evt, evtlist)
return False
@classmethod
def _add(cls, obj):
if App._win != None:
App._win.add(obj.GFX)
App.spritelist.append(obj)
if type(obj) not in App._spritesdict:
App._spritesdict[type(obj)] = []
App._spritesdict[type(obj)].append(obj)
@classmethod
def _remove(cls, obj):
if App._win != None:
App._win.remove(obj.GFX)
App.spritelist.remove(obj)
App._spritesdict[type(obj)].remove(obj)
def _animate(self, dummy):
if self.userfunc:
self.userfunc()
else:
self.step()
App._win.animate(self._animate)
@classmethod
def _destroy(cls, *args):
"""
This will close the display window/tab, remove all references to
sprites and place the `App` class in a state in which a new
application could be instantiated.
"""
if App._win:
App._win.unbind(KeyEvent.keydown)
App._win.unbind(KeyEvent.keyup)
App._win.unbind(KeyEvent.keypress)
App._win.unbind(MouseEvent.mousewheel)
App._win.unbind(MouseEvent.mousemove)
App._win.unbind(MouseEvent.mousedown)
App._win.unbind(MouseEvent.mouseup)
App._win.unbind(MouseEvent.click)
App._win.unbind(MouseEvent.dblclick)
App._win.destroy()
App._win = None
for s in list(App.spritelist):
s.destroy()
App.spritelist = []
App._spritesdict = {}
App._eventdict = {}
App._spritesadded = False
@classmethod
def listenKeyEvent(cls, eventtype, key, callback):
"""
Register to receive keyboard events. The `eventtype` parameter is a
string that indicates what type of key event to receive (value is one
of: `'keydown'`, `'keyup'` or `'keypress'`). The `key` parameter is a
string indicating which key (e.g. `'space'`, `'left arrow'`, etc.) to
receive events for. The `callback` parameter is a reference to a
function or method that will be called with the `ggame.KeyEvent` object
when the event occurs.
See the source for `ggame.KeyEvent.keys` for a list of key names
to use with the `key` paramter.
"""
evtlist = App._eventdict.get((eventtype, key), [])
if not callback in evtlist:
evtlist.append(callback)
App._eventdict[(eventtype, key)] = evtlist
@classmethod
def listenMouseEvent(cls, eventtype, callback):
"""
Register to receive mouse events. The `eventtype` parameter is
a string that indicates what type of mouse event to receive (
value is one of: `'mousemove'`, `'mousedown'`, `'mouseup'`, `'click'`,
`'dblclick'` or `'mousewheel'`). The `callback` parameter is a
reference to a function or method that will be called with the
`ggame.MouseEvent` object when the event occurs.
"""
evtlist = App._eventdict.get(eventtype, [])
if not callback in evtlist:
evtlist.append(callback)
App._eventdict[eventtype] = evtlist
@classmethod
def unlistenKeyEvent(cls, eventtype, key, callback):
"""
Use this method to remove a registration to receive a particular
keyboard event. Arguments must exactly match those used when
registering for the event.
"""
App._eventdict[(eventtype,key)].remove(callback)
@classmethod
def unlistenMouseEvent(cls, eventtype, callback):
"""
Use this method to remove a registration to receive a particular
mouse event. Arguments must exactly match those used when
registering for the event.
"""
App._eventdict[eventtype].remove(callback)
@classmethod
def getSpritesbyClass(cls, sclass):
"""
Returns a list of all active sprites of a given class.
"""
return App._spritesdict.get(sclass, [])
def step(self):
"""
The `ggame.App.step` method is called once per animation frame. Override
this method in your own subclass of `ggame.App` to perform periodic
calculations, such as checking for sprite collisions, or calling
'step' functions in your own customized sprite classes.
The base class `ggame.App.step` method is empty and is intended to be overriden.
"""
pass
def run(self, userfunc = None):
"""
Calling the `ggame.App.run` method begins the animation process whereby the
`ggame.App.step` method is called once per animation frame. Set `userfunc`
to any function which shall be called once per animation frame.
"""
self.userfunc = userfunc
App._win.animate(self._animate)
Ancestors (in MRO)
- App
- builtins.object
Class variables
var spritelist
List of all sprites currently active in the application.
Static methods
def __init__(
self, *args)
The App
class is called either by specifying the desired app window size
in pixels, as two parameters (e.g. myapp = App(640,480)
), or by providing
no size parameters at all (e.g. myapp = App()
), in which case, the full browser
window size is used.
def __init__(self, *args):
"""
The `ggame.App` class is called either by specifying the desired app window size
in pixels, as two parameters (e.g. `myapp = App(640,480)`), or by providing
no size parameters at all (e.g. `myapp = App()`), in which case, the full browser
window size is used.
"""
if App._win == None and (len(args) == 0 or len(args) == 2):
x = y = 0
if len(args) == 2:
x = args[0]
y = args[1]
App._win = GFX_Window(x, y, type(self)._destroy)
self.width = App._win.width
self.height = App._win.height
# Add existing sprites to the window
if not App._spritesadded and len(App.spritelist) > 0:
App._spritesadded = True
for sprite in App.spritelist:
App._win.add(sprite.GFX)
App._win.bind(KeyEvent.keydown, self._keyEvent)
App._win.bind(KeyEvent.keyup, self._keyEvent)
App._win.bind(KeyEvent.keypress, self._keyEvent)
App._win.bind(MouseEvent.mousewheel, self._mouseEvent)
App._win.bind(MouseEvent.mousemove, self._mouseEvent)
App._win.bind(MouseEvent.mousedown, self._mouseEvent)
App._win.bind(MouseEvent.mouseup, self._mouseEvent)
App._win.bind(MouseEvent.click, self._mouseEvent)
App._win.bind(MouseEvent.dblclick, self._mouseEvent)
def run(
self, userfunc=None)
Calling the run
method begins the animation process whereby the
step
method is called once per animation frame. Set userfunc
to any function which shall be called once per animation frame.
def run(self, userfunc = None):
"""
Calling the `ggame.App.run` method begins the animation process whereby the
`ggame.App.step` method is called once per animation frame. Set `userfunc`
to any function which shall be called once per animation frame.
"""
self.userfunc = userfunc
App._win.animate(self._animate)
def step(
self)
The step
method is called once per animation frame. Override
this method in your own subclass of App
to perform periodic
calculations, such as checking for sprite collisions, or calling
'step' functions in your own customized sprite classes.
The base class step
method is empty and is intended to be overriden.
def step(self):
"""
The `ggame.App.step` method is called once per animation frame. Override
this method in your own subclass of `ggame.App` to perform periodic
calculations, such as checking for sprite collisions, or calling
'step' functions in your own customized sprite classes.
The base class `ggame.App.step` method is empty and is intended to be overriden.
"""
pass
Methods
def getSpritesbyClass(
cls, sclass)
Returns a list of all active sprites of a given class.
@classmethod
def getSpritesbyClass(cls, sclass):
"""
Returns a list of all active sprites of a given class.
"""
return App._spritesdict.get(sclass, [])
def listenKeyEvent(
cls, eventtype, key, callback)
Register to receive keyboard events. The eventtype
parameter is a
string that indicates what type of key event to receive (value is one
of: 'keydown'
, 'keyup'
or 'keypress'
). The key
parameter is a
string indicating which key (e.g. 'space'
, 'left arrow'
, etc.) to
receive events for. The callback
parameter is a reference to a
function or method that will be called with the KeyEvent
object
when the event occurs.
See the source for keys
for a list of key names
to use with the key
paramter.
@classmethod
def listenKeyEvent(cls, eventtype, key, callback):
"""
Register to receive keyboard events. The `eventtype` parameter is a
string that indicates what type of key event to receive (value is one
of: `'keydown'`, `'keyup'` or `'keypress'`). The `key` parameter is a
string indicating which key (e.g. `'space'`, `'left arrow'`, etc.) to
receive events for. The `callback` parameter is a reference to a
function or method that will be called with the `ggame.KeyEvent` object
when the event occurs.
See the source for `ggame.KeyEvent.keys` for a list of key names
to use with the `key` paramter.
"""
evtlist = App._eventdict.get((eventtype, key), [])
if not callback in evtlist:
evtlist.append(callback)
App._eventdict[(eventtype, key)] = evtlist
def listenMouseEvent(
cls, eventtype, callback)
Register to receive mouse events. The eventtype
parameter is
a string that indicates what type of mouse event to receive (
value is one of: 'mousemove'
, 'mousedown'
, 'mouseup'
, 'click'
,
'dblclick'
or 'mousewheel'
). The callback
parameter is a
reference to a function or method that will be called with the
MouseEvent
object when the event occurs.
@classmethod
def listenMouseEvent(cls, eventtype, callback):
"""
Register to receive mouse events. The `eventtype` parameter is
a string that indicates what type of mouse event to receive (
value is one of: `'mousemove'`, `'mousedown'`, `'mouseup'`, `'click'`,
`'dblclick'` or `'mousewheel'`). The `callback` parameter is a
reference to a function or method that will be called with the
`ggame.MouseEvent` object when the event occurs.
"""
evtlist = App._eventdict.get(eventtype, [])
if not callback in evtlist:
evtlist.append(callback)
App._eventdict[eventtype] = evtlist
def unlistenKeyEvent(
cls, eventtype, key, callback)
Use this method to remove a registration to receive a particular keyboard event. Arguments must exactly match those used when registering for the event.
@classmethod
def unlistenKeyEvent(cls, eventtype, key, callback):
"""
Use this method to remove a registration to receive a particular
keyboard event. Arguments must exactly match those used when
registering for the event.
"""
App._eventdict[(eventtype,key)].remove(callback)
def unlistenMouseEvent(
cls, eventtype, callback)
Use this method to remove a registration to receive a particular mouse event. Arguments must exactly match those used when registering for the event.
@classmethod
def unlistenMouseEvent(cls, eventtype, callback):
"""
Use this method to remove a registration to receive a particular
mouse event. Arguments must exactly match those used when
registering for the event.
"""
App._eventdict[eventtype].remove(callback)
class CircleAsset
The CircleAsset
is a "virtual" asset that is created on the
fly without requiring creation of an image file.
class CircleAsset(_ShapeAsset):
"""
The `ggame.CircleAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, radius, line=blackline, fill=black):
"""
Creation of a `ggame.CircleAsset` requires specification of the circle
`radius` in pixels, the `line` (as a proper `ggame.LineStyle` instance)
and fill properties (as a `ggame.Color` instance).
"""
super().__init__(line, fill)
self.radius = radius
self.GFX = GFX_Graphics.drawCircle(0, 0, self.radius).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
Ancestors (in MRO)
- CircleAsset
- __pdoc_file_module__._ShapeAsset
- __pdoc_file_module__._CurveAsset
- __pdoc_file_module__._GraphicsAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, radius, line=<__pdoc_file_module__.LineStyle object at 0x7f8eacdd9eb8>, fill=<__pdoc_file_module__.Color object at 0x7f8eacdd9d30>)
Creation of a CircleAsset
requires specification of the circle
radius
in pixels, the line
(as a proper LineStyle
instance)
and fill properties (as a Color
instance).
def __init__(self, radius, line=blackline, fill=black):
"""
Creation of a `ggame.CircleAsset` requires specification of the circle
`radius` in pixels, the `line` (as a proper `ggame.LineStyle` instance)
and fill properties (as a `ggame.Color` instance).
"""
super().__init__(line, fill)
self.radius = radius
self.GFX = GFX_Graphics.drawCircle(0, 0, self.radius).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
The GFX
property represents the underlying system object.
var radius
class Color
The Color
class is used to represent colors and/or colors with
transparency.
class Color(object):
"""
The `ggame.Color` class is used to represent colors and/or colors with
transparency.
"""
def __init__(self, color, alpha):
"""
A `ggame.Color` instance must specify both a `color` as an integer
in the conventional format (usually as a hexadecimal literal, e.g.
0xffbb33 that represents the three color components, red, green
and blue), and a transparency value, or `alpha` as a floating
point number in the range of 0.0 to 1.0 where 0.0 represents
completely transparent and 1.0 represents completely solid.
Example: `red = Color(0xff0000, 1.0)`
"""
self.color = color
self.alpha = alpha
def __eq__(self, other):
return type(self) is type(other) and self.color == other.color and self.alpha == other.alpha
Ancestors (in MRO)
- Color
- builtins.object
Static methods
def __init__(
self, color, alpha)
A Color
instance must specify both a color
as an integer
in the conventional format (usually as a hexadecimal literal, e.g.
0xffbb33 that represents the three color components, red, green
and blue), and a transparency value, or alpha
as a floating
point number in the range of 0.0 to 1.0 where 0.0 represents
completely transparent and 1.0 represents completely solid.
Example: red = Color(0xff0000, 1.0)
def __init__(self, color, alpha):
"""
A `ggame.Color` instance must specify both a `color` as an integer
in the conventional format (usually as a hexadecimal literal, e.g.
0xffbb33 that represents the three color components, red, green
and blue), and a transparency value, or `alpha` as a floating
point number in the range of 0.0 to 1.0 where 0.0 represents
completely transparent and 1.0 represents completely solid.
Example: `red = Color(0xff0000, 1.0)`
"""
self.color = color
self.alpha = alpha
Instance variables
var alpha
var color
class EllipseAsset
The EllipseAsset
is a "virtual" asset that is created on the
fly without requiring creation of an image file.
class EllipseAsset(_ShapeAsset):
"""
The `ggame.EllipseAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, halfw, halfh, line=blackline, fill=black):
"""
Creation of a `ggame.EllipseAsset` requires specification of the ellipse
`halfw`, or semi-axis length in the horizontal direction (half of the
ellipse width) and the `halfh`, or semi-axis length in the vertical direction.
`line` (as `ggame.LineStyle` instance) and `fill` (as `ggame.Color` instance)
must also be provided.
"""
super().__init__(line, fill)
self.halfw = halfw
self.halfh = halfh
self.GFX = GFX_Graphics.drawEllipse(0, 0, self.halfw, self.halfh).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
Ancestors (in MRO)
- EllipseAsset
- __pdoc_file_module__._ShapeAsset
- __pdoc_file_module__._CurveAsset
- __pdoc_file_module__._GraphicsAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, halfw, halfh, line=<__pdoc_file_module__.LineStyle object at 0x7f8eacdd9eb8>, fill=<__pdoc_file_module__.Color object at 0x7f8eacdd9d30>)
Creation of a EllipseAsset
requires specification of the ellipse
halfw
, or semi-axis length in the horizontal direction (half of the
ellipse width) and the halfh
, or semi-axis length in the vertical direction.
line
(as LineStyle
instance) and fill
(as Color
instance)
must also be provided.
def __init__(self, halfw, halfh, line=blackline, fill=black):
"""
Creation of a `ggame.EllipseAsset` requires specification of the ellipse
`halfw`, or semi-axis length in the horizontal direction (half of the
ellipse width) and the `halfh`, or semi-axis length in the vertical direction.
`line` (as `ggame.LineStyle` instance) and `fill` (as `ggame.Color` instance)
must also be provided.
"""
super().__init__(line, fill)
self.halfw = halfw
self.halfh = halfh
self.GFX = GFX_Graphics.drawEllipse(0, 0, self.halfw, self.halfh).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
The GFX
property represents the underlying system object.
var halfh
var halfw
class Frame
Frame is a utility class for expressing the idea of a rectangular region.
class Frame(object):
"""
Frame is a utility class for expressing the idea of a rectangular region.
"""
def __init__(self, x, y, w, h):
"""
Initialization for the `ggame.Frame` objects.
`x` and `y` are coordinates of the upper left hand corner of the frame.
`w` and `h` are the width and height of the frame rectangle.
"""
self.GFX = GFX_Rectangle(x,y,w,h)
"""
`GFX` is a reference to the underlying object provided by the system.
"""
self.x = x
"""
X-coordinate of the upper left hand corner of this `ggame.Frame`.
"""
self.y = y
"""
Y-coordinate of the upper left hand corner of this `ggame.Frame`.
"""
self.w = w
"""
Width of the `ggame.Frame`.
"""
self.h = h
"""
Height of the `ggame.Frame`.
"""
@property
def x(self):
return self.GFX.x
@x.setter
def x(self, value):
self.GFX.x = value
@property
def y(self):
return self.GFX.y
@y.setter
def y(self, value):
self.GFX.y = value
@property
def w(self):
return self.GFX.width
@w.setter
def w(self, value):
self.GFX.width = value
@property
def h(self):
return self.GFX.height
@h.setter
def h(self, value):
self.GFX.height = value
@property
def center(self):
"""
`center` property computes a coordinate pair (tuple) for the
center of the frame.
The `center` property, when set, redefines the `x` and `y` properties
of the frame in order to make the center agree with the coordinates
(tuple) assigned to it.
"""
return (self.x + self.w//2, self.y + self.h//2)
@center.setter
def center(self, value):
c = self.center
self.x += value[0] - c[0]
self.y += value[1] - c[1]
Ancestors (in MRO)
- Frame
- builtins.object
Static methods
def __init__(
self, x, y, w, h)
Initialization for the Frame
objects.
x
and y
are coordinates of the upper left hand corner of the frame.
w
and h
are the width and height of the frame rectangle.
def __init__(self, x, y, w, h):
"""
Initialization for the `ggame.Frame` objects.
`x` and `y` are coordinates of the upper left hand corner of the frame.
`w` and `h` are the width and height of the frame rectangle.
"""
self.GFX = GFX_Rectangle(x,y,w,h)
"""
`GFX` is a reference to the underlying object provided by the system.
"""
self.x = x
"""
X-coordinate of the upper left hand corner of this `ggame.Frame`.
"""
self.y = y
"""
Y-coordinate of the upper left hand corner of this `ggame.Frame`.
"""
self.w = w
"""
Width of the `ggame.Frame`.
"""
self.h = h
"""
Height of the `ggame.Frame`.
"""
Instance variables
var GFX
GFX
is a reference to the underlying object provided by the system.
var center
center
property computes a coordinate pair (tuple) for the
center of the frame.
The center
property, when set, redefines the x
and y
properties
of the frame in order to make the center agree with the coordinates
(tuple) assigned to it.
class ImageAsset
The ImageAsset
class connects ggame to a specific image file.
class ImageAsset(_Asset):
"""
The `ImageAsset` class connects ggame to a specific image **file**.
"""
def __init__(self, url, frame=None, qty=1, direction='horizontal', margin=0):
"""
All `ggame.ImageAsset` instances must specify a file name or url with
the `url` parameter.
If the desired sprite image exists in only a smaller sub-section of the
original image, then the are can be specified by providing the
`frame` parameter, which must be a valid `ggame.Frame` object.
If image file actually is a *collection* of images, such as a so-called
*sprite sheet*, then the `ImageAsset` class supports defining a list
of images, provided they exist in the original image as a **row**
of evenly spaced images or a **column** of images. To specify this,
provide the `qty` (quantity) of images in the row or column, the
`direction` of the list ('horizontal' or 'vertical' are supported),
and an optional `margin`, if there is a gap between successive
images. When used in this way, the `frame` parameter must define the
area of the **first** image in the collection; all subsequent images
in the list are assumed to be the same size.
"""
super().__init__()
self.url = url
"""
A string that represents the path or url of the original file.
"""
del self.GFXlist[0]
self.width = self.height = 0
self.append(url, frame, qty, direction, margin)
def _subframe(self, texture, frame):
return GFX_Texture(texture, frame.GFX)
def append(self, url, frame=None, qty=1, direction='horizontal', margin=0):
"""
Append a texture asset from a new image file (or url). This method
allows you to build a collection of images into an asset (such as you
might need for an animated sprite), but without using a single
sprite sheet image.
The parameters for the `append` method are identical to those
supplied to the `ggame.ImageAsset` initialization method.
This method allows you to build up an asset that consists of
multiple rows or columns of images in a sprite sheet or sheets.
"""
GFX = GFX_Texture_fromImage(url, False)
dx = 0
dy = 0
for i in range(qty):
if not frame is None:
self.width = frame.w
self.height = frame.h
if direction == 'horizontal':
dx = frame.w + margin
elif direction == 'vertical':
dy = frame.h + margin
f = Frame(frame.x + dx * i, frame.y + dy * i, frame.w, frame.h)
GFX = self._subframe(GFX, f)
else:
self.width = GFX.width
self.height = GFX.height
self.GFXlist.append(GFX)
Ancestors (in MRO)
- ImageAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, url, frame=None, qty=1, direction='horizontal', margin=0)
All ImageAsset
instances must specify a file name or url with
the url
parameter.
If the desired sprite image exists in only a smaller sub-section of the
original image, then the are can be specified by providing the
frame
parameter, which must be a valid Frame
object.
If image file actually is a collection of images, such as a so-called
sprite sheet, then the ImageAsset
class supports defining a list
of images, provided they exist in the original image as a row
of evenly spaced images or a column of images. To specify this,
provide the qty
(quantity) of images in the row or column, the
direction
of the list ('horizontal' or 'vertical' are supported),
and an optional margin
, if there is a gap between successive
images. When used in this way, the frame
parameter must define the
area of the first image in the collection; all subsequent images
in the list are assumed to be the same size.
def __init__(self, url, frame=None, qty=1, direction='horizontal', margin=0):
"""
All `ggame.ImageAsset` instances must specify a file name or url with
the `url` parameter.
If the desired sprite image exists in only a smaller sub-section of the
original image, then the are can be specified by providing the
`frame` parameter, which must be a valid `ggame.Frame` object.
If image file actually is a *collection* of images, such as a so-called
*sprite sheet*, then the `ImageAsset` class supports defining a list
of images, provided they exist in the original image as a **row**
of evenly spaced images or a **column** of images. To specify this,
provide the `qty` (quantity) of images in the row or column, the
`direction` of the list ('horizontal' or 'vertical' are supported),
and an optional `margin`, if there is a gap between successive
images. When used in this way, the `frame` parameter must define the
area of the **first** image in the collection; all subsequent images
in the list are assumed to be the same size.
"""
super().__init__()
self.url = url
"""
A string that represents the path or url of the original file.
"""
del self.GFXlist[0]
self.width = self.height = 0
self.append(url, frame, qty, direction, margin)
def append(
self, url, frame=None, qty=1, direction='horizontal', margin=0)
Append a texture asset from a new image file (or url). This method allows you to build a collection of images into an asset (such as you might need for an animated sprite), but without using a single sprite sheet image.
The parameters for the append
method are identical to those
supplied to the ImageAsset
initialization method.
This method allows you to build up an asset that consists of multiple rows or columns of images in a sprite sheet or sheets.
def append(self, url, frame=None, qty=1, direction='horizontal', margin=0):
"""
Append a texture asset from a new image file (or url). This method
allows you to build a collection of images into an asset (such as you
might need for an animated sprite), but without using a single
sprite sheet image.
The parameters for the `append` method are identical to those
supplied to the `ggame.ImageAsset` initialization method.
This method allows you to build up an asset that consists of
multiple rows or columns of images in a sprite sheet or sheets.
"""
GFX = GFX_Texture_fromImage(url, False)
dx = 0
dy = 0
for i in range(qty):
if not frame is None:
self.width = frame.w
self.height = frame.h
if direction == 'horizontal':
dx = frame.w + margin
elif direction == 'vertical':
dy = frame.h + margin
f = Frame(frame.x + dx * i, frame.y + dy * i, frame.w, frame.h)
GFX = self._subframe(GFX, f)
else:
self.width = GFX.width
self.height = GFX.height
self.GFXlist.append(GFX)
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
GFX
property represents the underlying system object used to represent
this asset. If this asset is composed of multiple assets, then the first
asset is referenced by GFX
.
var url
A string that represents the path or url of the original file.
class KeyEvent
The KeyEvent
class encapsulates information regarding a user keyboard
action that is being reported by the system.
class KeyEvent(_Event):
"""
The `ggame.KeyEvent` class encapsulates information regarding a user keyboard
action that is being reported by the system.
"""
no_location = 0
"""Constant indicating no specific location for the key event."""
right_location = 2
"""Constant indicating the key event was on the right hand side of the keyboard."""
left_location = 1
"""Constant indicating the key event was on the left hand side of the keyboard."""
keydown = "keydown"
"""Constant indicating the key was pressed down."""
keyup = "keyup"
"""Constant indicating the key was released."""
keypress = "keypress"
"""Constant indicating the combination of keydown, followed by keyup."""
keys = {8: 'backspace',
9: 'tab',
13: 'enter',
16: 'shift',
17: 'ctrl',
18: 'alt',
19: 'pause/break',
20: 'caps lock',
27: 'escape',
32: 'space',
33: 'page up',
34: 'page down',
35: 'end',
36: 'home',
37: 'left arrow',
38: 'up arrow',
39: 'right arrow',
40: 'down arrow',
45: 'insert',
46: 'delete',
48: '0',
49: '1',
50: '2',
51: '3',
52: '4',
53: '5',
54: '6',
55: '7',
56: '8',
57: '9',
65: 'a',
66: 'b',
67: 'c',
68: 'd',
69: 'e',
70: 'f',
71: 'g',
72: 'h',
73: 'i',
74: 'j',
75: 'k',
76: 'l',
77: 'm',
78: 'n',
79: 'o',
80: 'p',
81: 'q',
82: 'r',
83: 's',
84: 't',
85: 'u',
86: 'v',
87: 'w',
88: 'x',
89: 'y',
90: 'z',
91: 'left window key',
92: 'right window key',
93: 'select key',
96: 'numpad 0',
97: 'numpad 1',
98: 'numpad 2',
99: 'numpad 3',
100: 'numpad 4',
101: 'numpad 5',
102: 'numpad 6',
103: 'numpad 7',
104: 'numpad 8',
105: 'numpad 9',
106: 'multiply',
107: 'add',
109: 'subtract',
110: 'decimal point',
111: 'divide',
112: 'f1',
113: 'f2',
114: 'f3',
115: 'f4',
116: 'f5',
117: 'f6',
118: 'f7',
119: 'f8',
120: 'f9',
121: 'f10',
122: 'f11',
123: 'f12',
144: 'num lock',
145: 'scroll lock',
186: 'semicolon',
187: 'equal sign',
188: 'comma',
189: 'dash',
190: 'period',
191: 'forward slash',
192: 'grave accent',
219: 'open bracket',
220: 'back slash',
221: 'close bracket',
222: 'single quote'}
"""Dictionary mapping key code integers to textual key description."""
def __init__(self, hwevent):
"""
The event is initialized by the system, with a `hwevent` input parameter.
"""
super().__init__(hwevent)
self.keynum = hwevent.keyCode
"""The `keynum` attribute identifies a keycode (number)."""
self.key = self.keys[hwevent.keyCode]
"""The `key` attribute identifes the key in text form (e.g. 'back slash')."""
Ancestors (in MRO)
- KeyEvent
- __pdoc_file_module__._Event
- builtins.object
Class variables
var keydown
Constant indicating the key was pressed down.
var keypress
Constant indicating the combination of keydown, followed by keyup.
var keys
Dictionary mapping key code integers to textual key description.
var keyup
Constant indicating the key was released.
var left_location
Constant indicating the key event was on the left hand side of the keyboard.
var no_location
Constant indicating no specific location for the key event.
var right_location
Constant indicating the key event was on the right hand side of the keyboard.
Static methods
def __init__(
self, hwevent)
The event is initialized by the system, with a hwevent
input parameter.
def __init__(self, hwevent):
"""
The event is initialized by the system, with a `hwevent` input parameter.
"""
super().__init__(hwevent)
self.keynum = hwevent.keyCode
"""The `keynum` attribute identifies a keycode (number)."""
self.key = self.keys[hwevent.keyCode]
"""The `key` attribute identifes the key in text form (e.g. 'back slash')."""
Instance variables
var key
The key
attribute identifes the key in text form (e.g. 'back slash').
var keynum
The keynum
attribute identifies a keycode (number).
class LineAsset
The LineAsset
is a "virtual" asset that is created on the
fly without requiring creation of an image file. A LineAsset
instance
represents a single line segment.
class LineAsset(_CurveAsset):
"""
The `ggame.LineAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file. A `LineAsset` instance
represents a single line segment.
"""
def __init__(self, x, y, line=blackline):
"""
Creation of a `ggame.LineAsset` requires specification of an `x` and
`y` coordinate for the endpoint of the line. The starting point of the
line is implied as coordinates (0,0). Note that when this asset is
used in a `ggame.Sprite` class, the sprite's `x` and `y` coordinates
will control the location of the line segment on the screen.
As the `ggame.LineAsset` does not cover a region, only a `ggame.LineStyle`
argument must be supplied (`line`).
"""
super().__init__(line)
self.deltaX = x
"""This attribute represents the `x` parameter supplied during instantiation."""
self.deltaY = y
"""This attribute represents the `y` parameter supplied during instantiation."""
GFX_Graphics.moveTo(0, 0)
self.GFX = GFX_Graphics.lineTo(self.deltaX, self.deltaY).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
Ancestors (in MRO)
- LineAsset
- __pdoc_file_module__._CurveAsset
- __pdoc_file_module__._GraphicsAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, x, y, line=<__pdoc_file_module__.LineStyle object at 0x7f8eacdd9eb8>)
Creation of a LineAsset
requires specification of an x
and
y
coordinate for the endpoint of the line. The starting point of the
line is implied as coordinates (0,0). Note that when this asset is
used in a Sprite
class, the sprite's x
and y
coordinates
will control the location of the line segment on the screen.
As the LineAsset
does not cover a region, only a LineStyle
argument must be supplied (line
).
def __init__(self, x, y, line=blackline):
"""
Creation of a `ggame.LineAsset` requires specification of an `x` and
`y` coordinate for the endpoint of the line. The starting point of the
line is implied as coordinates (0,0). Note that when this asset is
used in a `ggame.Sprite` class, the sprite's `x` and `y` coordinates
will control the location of the line segment on the screen.
As the `ggame.LineAsset` does not cover a region, only a `ggame.LineStyle`
argument must be supplied (`line`).
"""
super().__init__(line)
self.deltaX = x
"""This attribute represents the `x` parameter supplied during instantiation."""
self.deltaY = y
"""This attribute represents the `y` parameter supplied during instantiation."""
GFX_Graphics.moveTo(0, 0)
self.GFX = GFX_Graphics.lineTo(self.deltaX, self.deltaY).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
The GFX
property represents the underlying system object.
var deltaX
This attribute represents the x
parameter supplied during instantiation.
var deltaY
This attribute represents the y
parameter supplied during instantiation.
class LineStyle
The LineStyle
class is used to represent line style when
drawing geometrical objects such as rectangles, ellipses, etc.
class LineStyle(object):
"""
The `ggame.LineStyle` class is used to represent line style when
drawing geometrical objects such as rectangles, ellipses, etc.
"""
def __init__(self, width, color):
"""
When creating a `ggame.LineStyle` instances you must specify
the `width` of the line in pixels and the `color` as a valid
`ggame.Color` instance.
Example: `line = LineStyle(3, Color(0x00ff00, 1.0))` will define
a 3 pixel wide green line.
"""
self.width = width
self.color = color
def __eq__(self, other):
return type(self) is type(other) and self.width == other.width and self.color == other.color
Ancestors (in MRO)
- LineStyle
- builtins.object
Static methods
def __init__(
self, width, color)
When creating a LineStyle
instances you must specify
the width
of the line in pixels and the color
as a valid
Color
instance.
Example: line = LineStyle(3, Color(0x00ff00, 1.0))
will define
a 3 pixel wide green line.
def __init__(self, width, color):
"""
When creating a `ggame.LineStyle` instances you must specify
the `width` of the line in pixels and the `color` as a valid
`ggame.Color` instance.
Example: `line = LineStyle(3, Color(0x00ff00, 1.0))` will define
a 3 pixel wide green line.
"""
self.width = width
self.color = color
Instance variables
var color
var width
class MouseEvent
The MouseEvent
class encapsulates information regarding a user mouse
action that is being reported by the system.
class MouseEvent(_Event):
"""
The `ggame.MouseEvent` class encapsulates information regarding a user mouse
action that is being reported by the system.
"""
mousemove = "mousemove"
"""Constant identifying a `mousemove` event."""
mousedown = "mousedown"
"""Constant identifying a `mousedown` event."""
mouseup = "mouseup"
"""Constant identifying a `mouseup` event."""
click = "click"
"""Constant identifying a button `click` event."""
dblclick = "dblclick"
"""Constant identifying a button `dblclick` event."""
mousewheel = "wheel"
"""Constant identifying a mouse `wheel` scroll event."""
def __init__(self, hwevent):
"""
The event is initialized by the system, with a `hwevent` input parameter.
"""
super().__init__(hwevent)
self.wheelDelta = 0
"""Integer representing up/down motion of the scroll wheel."""
if self.type == self.mousewheel:
self.wheelDelta = hwevent.deltaY
else:
self.wheelDelta = 0
rect = App._win._renderer.view.getBoundingClientRect()
xscale = App._win.width/rect.width
yscale = App._win.height/rect.height
self.x = (hwevent.clientX - rect.left) * xscale
"""The window x-coordinate of the mouse pointer when the event occurred."""
self.y = (hwevent.clientY - rect.top) * yscale
"""The window y-coordinate of the mouse pointer when the event occurred."""
Ancestors (in MRO)
- MouseEvent
- __pdoc_file_module__._Event
- builtins.object
Class variables
var click
Constant identifying a button click
event.
var dblclick
Constant identifying a button dblclick
event.
var mousedown
Constant identifying a mousedown
event.
var mousemove
Constant identifying a mousemove
event.
var mouseup
Constant identifying a mouseup
event.
var mousewheel
Constant identifying a mouse wheel
scroll event.
Static methods
def __init__(
self, hwevent)
The event is initialized by the system, with a hwevent
input parameter.
def __init__(self, hwevent):
"""
The event is initialized by the system, with a `hwevent` input parameter.
"""
super().__init__(hwevent)
self.wheelDelta = 0
"""Integer representing up/down motion of the scroll wheel."""
if self.type == self.mousewheel:
self.wheelDelta = hwevent.deltaY
else:
self.wheelDelta = 0
rect = App._win._renderer.view.getBoundingClientRect()
xscale = App._win.width/rect.width
yscale = App._win.height/rect.height
self.x = (hwevent.clientX - rect.left) * xscale
"""The window x-coordinate of the mouse pointer when the event occurred."""
self.y = (hwevent.clientY - rect.top) * yscale
"""The window y-coordinate of the mouse pointer when the event occurred."""
Instance variables
var wheelDelta
Integer representing up/down motion of the scroll wheel.
var x
The window x-coordinate of the mouse pointer when the event occurred.
var y
The window y-coordinate of the mouse pointer when the event occurred.
class PolygonAsset
The PolygonAsset
is a "virtual" asset that is created on the
fly without requiring creation of an image file.
class PolygonAsset(_ShapeAsset):
"""
The `ggame.PolygonAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, path, line=blackline, fill=black):
"""
Creation of a `ggame.PolygonAsset` requires specification of a
`path` consisting of a list of coordinate tuples. `line` and
`fill` arguments (instances of `ggame.LineStyle` and `ggame.Color`,
respectively) must also be supplied. The final coordinate in the
list must be the same as the first.
Example: `poly = PolygonAsset([(0,0), (50,50), (50,100), (0,0)], linesty, fcolor)`
"""
super().__init__(line, fill)
self.path = path
jpath = []
for point in self.path:
jpath.extend(point)
self.GFX = GFX_Graphics.drawPolygon(jpath).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
Ancestors (in MRO)
- PolygonAsset
- __pdoc_file_module__._ShapeAsset
- __pdoc_file_module__._CurveAsset
- __pdoc_file_module__._GraphicsAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, path, line=<__pdoc_file_module__.LineStyle object at 0x7f8eacdd9eb8>, fill=<__pdoc_file_module__.Color object at 0x7f8eacdd9d30>)
Creation of a PolygonAsset
requires specification of a
path
consisting of a list of coordinate tuples. line
and
fill
arguments (instances of LineStyle
and Color
,
respectively) must also be supplied. The final coordinate in the
list must be the same as the first.
Example: poly = PolygonAsset([(0,0), (50,50), (50,100), (0,0)], linesty, fcolor)
def __init__(self, path, line=blackline, fill=black):
"""
Creation of a `ggame.PolygonAsset` requires specification of a
`path` consisting of a list of coordinate tuples. `line` and
`fill` arguments (instances of `ggame.LineStyle` and `ggame.Color`,
respectively) must also be supplied. The final coordinate in the
list must be the same as the first.
Example: `poly = PolygonAsset([(0,0), (50,50), (50,100), (0,0)], linesty, fcolor)`
"""
super().__init__(line, fill)
self.path = path
jpath = []
for point in self.path:
jpath.extend(point)
self.GFX = GFX_Graphics.drawPolygon(jpath).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
The GFX
property represents the underlying system object.
var path
class RectangleAsset
The RectangleAsset
is a "virtual" asset that is created on the
fly without requiring creation of an image file.
class RectangleAsset(_ShapeAsset):
"""
The `ggame.RectangleAsset` is a "virtual" asset that is created on the
fly without requiring creation of an image file.
"""
def __init__(self, width, height, line=blackline, fill=black):
"""
Creation of a `ggame.RectangleAsset` requires specification of the
rectangle `width` and `height` in pixels, the `line` (as a proper
`ggame.LineStyle` instance) and fill properties (as a `ggame.Color`
instance).
"""
super().__init__(line, fill)
self.width = width
self.height = height
self.GFX = GFX_Graphics.drawRect(0, 0, self.width, self.height).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
Ancestors (in MRO)
- RectangleAsset
- __pdoc_file_module__._ShapeAsset
- __pdoc_file_module__._CurveAsset
- __pdoc_file_module__._GraphicsAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, width, height, line=<__pdoc_file_module__.LineStyle object at 0x7f8eacdd9eb8>, fill=<__pdoc_file_module__.Color object at 0x7f8eacdd9d30>)
Creation of a RectangleAsset
requires specification of the
rectangle width
and height
in pixels, the line
(as a proper
LineStyle
instance) and fill properties (as a Color
instance).
def __init__(self, width, height, line=blackline, fill=black):
"""
Creation of a `ggame.RectangleAsset` requires specification of the
rectangle `width` and `height` in pixels, the `line` (as a proper
`ggame.LineStyle` instance) and fill properties (as a `ggame.Color`
instance).
"""
super().__init__(line, fill)
self.width = width
self.height = height
self.GFX = GFX_Graphics.drawRect(0, 0, self.width, self.height).clone()
"""The `GFX` property represents the underlying system object."""
self.GFX.visible = False
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
The GFX
property represents the underlying system object.
var height
var width
class Sound
The Sound
class represents a sound, with methods for controlling
when and how the sound is played in the application.
class Sound(object):
"""
The `ggame.Sound` class represents a sound, with methods for controlling
when and how the sound is played in the application.
"""
def __init__(self, asset):
"""
Pass a valid `ggame.SoundAsset` instance when creating a `ggame.Sound` object.
"""
self.asset = asset
"""
A reference to the `ggame.SoundAsset` instance.
"""
self.SND = SND_Sound(self.asset.url)
"""
A reference to the underlying sound object provided by the system.
"""
self.SND.load()
def play(self):
"""
Play the sound once.
"""
self.stop()
self.SND.play()
def loop(self):
"""
Play the sound continuously, looping forever.
"""
self.stop()
self.SND.loop()
self.SND.play()
def stop(self):
"""
Stop playing the sound.
"""
self.SND.stop()
@property
def volume(self):
"""
The `ggame.Sound.volume` property is a number ranging from 0-100, that
represents the volume or intensity of the sound when it is playing.
"""
return self.SND.getVolume()
@volume.setter
def volume(self, value):
self.SND.setVolume(value)
Ancestors (in MRO)
- Sound
- builtins.object
Static methods
def __init__(
self, asset)
Pass a valid SoundAsset
instance when creating a Sound
object.
def __init__(self, asset):
"""
Pass a valid `ggame.SoundAsset` instance when creating a `ggame.Sound` object.
"""
self.asset = asset
"""
A reference to the `ggame.SoundAsset` instance.
"""
self.SND = SND_Sound(self.asset.url)
"""
A reference to the underlying sound object provided by the system.
"""
self.SND.load()
def loop(
self)
Play the sound continuously, looping forever.
def loop(self):
"""
Play the sound continuously, looping forever.
"""
self.stop()
self.SND.loop()
self.SND.play()
def play(
self)
Play the sound once.
def play(self):
"""
Play the sound once.
"""
self.stop()
self.SND.play()
def stop(
self)
Stop playing the sound.
def stop(self):
"""
Stop playing the sound.
"""
self.SND.stop()
Instance variables
var SND
A reference to the underlying sound object provided by the system.
var volume
The volume
property is a number ranging from 0-100, that
represents the volume or intensity of the sound when it is playing.
class SoundAsset
Class representing a single sound asset (sound file, such as .mp3 or .wav).
class SoundAsset(object):
"""
Class representing a single sound asset (sound file, such as .mp3 or .wav).
"""
def __init__(self, url):
"""
Create a `ggame.SoundAsset` instance by passing in the URL or file name
of the desired sound. Sound file formats may include `.wav` or `.mp3`, subject
to browser compatibility.
"""
self.url = url
"""
A string containing the url or name of the asset file.
"""
Ancestors (in MRO)
- SoundAsset
- builtins.object
Static methods
def __init__(
self, url)
Create a SoundAsset
instance by passing in the URL or file name
of the desired sound. Sound file formats may include .wav
or .mp3
, subject
to browser compatibility.
def __init__(self, url):
"""
Create a `ggame.SoundAsset` instance by passing in the URL or file name
of the desired sound. Sound file formats may include `.wav` or `.mp3`, subject
to browser compatibility.
"""
self.url = url
"""
A string containing the url or name of the asset file.
"""
Instance variables
var url
A string containing the url or name of the asset file.
class Sprite
The Sprite
class combines the idea of a visual/graphical asset, a
position on the screen, and behavior. Although the Sprite
can be
used as-is, it is generally subclassed to give it the desired behavior.
When subclassing the Sprite
class, you may customize the initialization
code to use a specific asset. A 'step' or 'poll' method may be added
for handling per-frame actions (e.g. checking for collisions). Step or poll
functions are not automatically called by the App
class, but you
may subclass the App
class in order to do this.
Furthermore, you may wish to define event callback methods in your customized sprite class. With customized creation, event handling, and periodic processing you can achieve fully autonomous behavior for your class.
class Sprite(object):
"""
The `ggame.Sprite` class combines the idea of a visual/graphical asset, a
position on the screen, and *behavior*. Although the `ggame.Sprite` can be
used as-is, it is generally subclassed to give it the desired behavior.
When subclassing the `ggame.Sprite` class, you may customize the initialization
code to use a specific asset. A 'step' or 'poll' method may be added
for handling per-frame actions (e.g. checking for collisions). Step or poll
functions are not automatically called by the `ggame.App` class, but you
may subclass the `ggame.App` class in order to do this.
Furthermore, you may wish to define event callback methods in your customized
sprite class. With customized creation, event handling, and periodic processing
you can achieve fully autonomous behavior for your class.
"""
_rectCollision = "rect"
_circCollision = "circ"
def __init__(self, asset, pos=(0,0), edgedef=None):
"""
The `ggame.Sprite` must be created with an existing graphical `asset`.
An optional `pos` or position may be provided, which specifies the
starting (x,y) coordinates of the sprite on the screen. By default,
the position of a sprite defines the location of its upper-left hand
corner. This behavior can be modified by customizing the `center` of
the sprite.
An optional `edgedef` or edge definition may be provided, which
specifies an asset that will be used to define the boundaries of
the sprite for the purpose of collision detection. If no `edgedef`
asset is given, the Sprite asset is used, which will be a rectangular
asset in the case of an image texture. This option is typically used
to define a visible image outline for a texture-based sprite that has
a transparent texture image background.
Example: player = Sprite(ImageAsset("player.png", (100,100), CircleAsset(50))
This creates a sprite using the `player.png` image, positioned with its
upper left corner at coordinates (100,100) and with a 50 pixel radius
circular collision border.
"""
self._index = 0
if type(asset) == ImageAsset:
self.asset = asset
try:
#self.GFX = GFX_Sprite()
self.GFX = GFX_Sprite(asset.GFX) # GFX is PIXI Sprite
except:
self.GFX = None
elif type(asset) in [RectangleAsset,
CircleAsset,
EllipseAsset,
PolygonAsset,
LineAsset,
]:
self.asset = asset
self.GFX = GFX_Sprite(asset.GFX.generateTexture())
#self.GFX = asset.GFX.clone() # GFX is PIXI Graphics (from Sprite)
#self.GFX.visible = True
elif type(asset) in [TextAsset]:
self.asset = asset._clone()
self.GFX = self.asset.GFX # GFX is PIXI Text (from Sprite)
self.GFX.visible = True
if not edgedef:
self.edgedef = asset
else:
self.edgedef = edgedef
self.xmin = self.xmax = self.ymin = self.ymax = 0
self.position = pos
"""Tuple indicates the position of the sprite on the screen."""
self._extentsdirty = True
"""Boolean indicates if extents must be calculated before collision test"""
self._createBaseVertices()
self._setExtents()
"""Initialize the extents (xmax, xmin, etc.) for collision detection"""
App._add(self)
def _createBaseVertices(self):
"""
Create sprite-relative list of vertex coordinates for boundary
"""
self._basevertices = []
assettype = type(self.edgedef)
if assettype in [RectangleAsset, ImageAsset, TextAsset]:
self._basevertices = [(0,0),
(0,self.edgedef.height),
(self.edgedef.width,self.edgedef.height),
(self.edgedef.width,0)]
elif assettype is PolygonAsset:
self._basevertices = self.edgedef.path[:-1]
elif assettype is LineAsset:
self._basevertices = [(0,0),
(self.edgedef.deltaX, self.edgedef.deltaY)]
elif assettype is EllipseAsset:
w = self.edgedef.halfw * 2
h = self.edgedef.halfh * 2
self._basevertices = [(0,0), (0,h), (w,h), (w,0)]
def _xformVertices(self):
"""
Create window-relative list of vertex coordinates for boundary
"""
# find center as sprite-relative points (note sprite may be scaled)
x = self.width * self.fxcenter / self.scale
y = self.height * self.fycenter / self.scale
if self.scale != 1.0:
sc = self.scale
# center-relative, scaled coordinates
crsc = [((xp-x)*sc,(yp-y)*sc) for xp,yp in self._basevertices]
else:
crsc = [(xp-x,yp-y) for xp,yp in self._basevertices]
# absolute, rotated coordinates
c = math.cos(self.rotation)
s = math.sin(self.rotation)
self._absolutevertices = [(self.x + x*c + y*s, self.y + -x*s + y*c)
for x,y in crsc]
def _setExtents(self):
"""
update min/max x and y based on position, center, width, height
"""
if self._extentsdirty:
if type(self.asset) is CircleAsset:
th = math.atan2(
self.fycenter - 0.5, 0.5 - self.fxcenter) + self.rotation
D = self.width
L = math.sqrt(math.pow(self.fxcenter - 0.5, 2) +
math.pow(self.fycenter - 0.5, 2)) * D
self.xmin = self.x + int(L*math.cos(th)) - D//2
self.ymin = self.y - int(L*math.sin(th)) - D//2
self.xmax = self.xmin + D
self.ymax = self.ymin + D
else:
# Build vertex list
self._xformVertices()
x, y = zip(*self._absolutevertices)
self.xmin = min(x)
self.xmax = max(x)
self.ymin = min(y)
self.ymax = max(y)
self._extentsdirty = False
def firstImage(self):
"""
Select and display the *first* image used by this sprite.
"""
self.GFX.texture = self.asset[0]
def lastImage(self):
"""
Select and display the *last* image used by this sprite.
"""
self.GFX.texture = self.asset[-1]
def nextImage(self, wrap = False):
"""
Select and display the *next* image used by this sprite.
If the current image is already the *last* image, then
the image is not advanced.
If the optional `wrap` parameter is set to `True`, then calling
`ggame.Sprite.nextImage` on the last image will cause the *first*
image to be loaded.
"""
self._index += 1
if self._index >= len(self.asset):
if wrap:
self._index = 0
else:
self._index = len(self.asset)-1
self.GFX.texture = self.asset[self._index]
def prevImage(self, wrap = False):
"""
Select and display the *previous* image used by this sprite.
If the current image is already the *first* image, then
the image is not changed.
If the optional `wrap` parameter is set to `True`, then calling
`ggame.Sprite.prevImage` on the first image will cause the *last*
image to be loaded.
"""
self._index -= 1
if self._index < 0:
if wrap:
self._index = len(self.asset)-1
else:
self._index = 0
self.GFX.texture = self.asset[self._index]
def setImage(self, index=0):
"""
Select the image to display by giving its `index`, where an index
of zero represents the *first* image in the asset.
This is equivalent to setting the `ggame.Sprite.index` property
directly.
"""
self.index = index
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def circularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
@property
def index(self):
"""This is an integer index in to the list of images available for this sprite."""
return self._index
@index.setter
def index(self, value):
self._index = value
try:
self.GFX.texture = self.asset[self._index]
except:
self._index = 0
self.GFX.texture = self.asset[self._index]
@property
def width(self):
"""
This is an integer representing the display width of the sprite.
Assigning a value to the width will scale the image horizontally.
"""
return self.GFX.width
@width.setter
def width(self, value):
self.GFX.width = value
self._extentsdirty = True
@property
def height(self):
"""
This is an integer representing the display height of the sprite.
Assigning a value to the height will scale the image vertically.
"""
return self.GFX.height
@height.setter
def height(self, value):
self.GFX.height = value
self._extentsdirty = True
@property
def x(self):
"""
This represents the x-coordinate of the sprite on the screen. Assigning
a value to this attribute will move the sprite horizontally.
"""
return self.GFX.position.x
@x.setter
def x(self, value):
deltax = value - self.GFX.position.x
self.xmax += deltax
self.xmin += deltax
"""Adjust extents directly with low overhead"""
self.GFX.position.x = value
@property
def y(self):
"""
This represents the y-coordinate of the sprite on the screen. Assigning
a value to this attribute will move the sprite vertically.
"""
return self.GFX.position.y
@y.setter
def y(self, value):
deltay = value - self.GFX.position.y
self.ymax += deltay
self.ymin += deltay
"""Adjust extents directly with low overhead"""
self.GFX.position.y = value
@property
def position(self):
"""
This represents the (x,y) coordinates of the sprite on the screen. Assigning
a value to this attribute will move the sprite to the new coordinates.
"""
return (self.GFX.position.x, self.GFX.position.y)
@position.setter
def position(self, value):
self.x, self.y = value
@property
def fxcenter(self):
"""
This represents the horizontal position of the sprite "center", as a floating
point number between 0.0 and 1.0. A value of 0.0 means that the x-coordinate
of the sprite refers to its left hand edge. A value of 1.0 refers to its
right hand edge. Any value in between may be specified. Values may be assigned
to this attribute.
"""
try:
return self.GFX.anchor.x
self._extentsdirty = True
except:
return 0.0
@fxcenter.setter
def fxcenter(self, value):
"""
Float: 0-1
"""
try:
self.GFX.anchor.x = value
self._extentsdirty = True
except:
pass
@property
def fycenter(self):
"""
This represents the vertical position of the sprite "center", as a floating
point number between 0.0 and 1.0. A value of 0.0 means that the x-coordinate
of the sprite refers to its top edge. A value of 1.0 refers to its
bottom edge. Any value in between may be specified. Values may be assigned
to this attribute.
"""
try:
return self.GFX.anchor.y
except:
return 0.0
@fycenter.setter
def fycenter(self, value):
"""
Float: 0-1
"""
try:
self.GFX.anchor.y = value
self._extentsdirty = True
except:
pass
@property
def center(self):
"""
This attribute represents the horizontal and vertical position of the
sprite "center" as a tuple of floating point numbers. See the
descriptions for `ggame.Sprite.fxcenter` and `ggame.Sprite.fycenter` for
more details.
"""
try:
return (self.GFX.anchor.x, self.GFX.anchor.y)
except:
return (0.0, 0.0)
@center.setter
def center(self, value):
try:
self.GFX.anchor.x = value[0]
self.GFX.anchor.y = value[1]
self._extentsdirty = True
except:
pass
@property
def visible(self):
"""
This boolean attribute may be used to change the visibility of the sprite. Setting
`ggame.Sprite.visible` to `False` will prevent the sprite from rendering on the
screen.
"""
return self.GFX.visible
@visible.setter
def visible(self, value):
self.GFX.visible = value
@property
def scale(self):
"""
This attribute may be used to change the size of the sprite ('scale' it) on the
screen. Value may be a floating point number. A value of 1.0 means that the sprite
image will keep its original size. A value of 2.0 would double it, etc.
"""
try:
return self.GFX.scale.x
except AttributeError:
return 1.0
@scale.setter
def scale(self, value):
self.GFX.scale.x = value
self.GFX.scale.y = value
self._extentsdirty = True
@property
def rotation(self):
"""
This attribute may be used to change the rotation of the sprite on the screen.
Value may be a floating point number. A value of 0.0 means no rotation. A value
of 1.0 means a rotation of 1 radian in a counter-clockwise direction. One radian
is 180/pi or approximately 57.3 degrees.
"""
try:
return -self.GFX.rotation
except AttributeError:
return 0.0
@rotation.setter
def rotation(self, value):
self.GFX.rotation = -value
if value:
self._extentsdirty = True
@classmethod
def collidingCircleWithPoly(cls, circ, poly):
return True
def collidingPolyWithPoly(self, obj):
return True
def collidingWith(self, obj):
"""
Return a boolean True if this sprite is currently overlapping the sprite
referenced by `obj`. Returns False if checking for collision with
itself. Returns False if extents of object make it impossible for
collision to occur. Returns True if sprite's `edgedef` parameter overlaps
with other sprite's `edgedef` parameter, taking into consideration both
sprites' center, rotation and scale settings.
"""
if self is obj:
return False
else:
self._setExtents()
obj._setExtents()
# Gross check for overlap will usually rule out a collision
if (self.xmin > obj.xmax
or self.xmax < obj.xmin
or self.ymin > obj.ymax
or self.ymax < obj.ymin):
return False
# Otherwise, perform a careful overlap determination
elif type(self.asset) is CircleAsset:
if type(obj.asset) is CircleAsset:
# two circles .. check distance between
sx = (self.xmin + self.xmax) / 2
sy = (self.ymin + self.ymax) / 2
ox = (obj.xmin + obj.xmax) / 2
oy = (obj.ymin + obj.ymax) / 2
d = math.sqrt((sx-ox)**2 + (sy-oy)**2)
return d <= self.width/2 + obj.width/2
else:
return self.collidingCircleWithPoly(self, obj)
else:
if type(obj.asset) is CircleAsset:
return self.collidingCircleWithPoly(obj, self)
else:
return self.collidingPolyWithPoly(obj)
def collidingWithSprites(self, sclass = None):
"""
Return a list of sprite objects identified by the `sclass` parameter
that are currently colliding with (that is, with which the `ggame.Sprite.collidingWith`
method returns True) this sprite. If `sclass` is set to `None` (default), then
all other sprites are checked for collision, otherwise, only sprites whose
class matches `sclass` are checked.
"""
if sclass is None:
slist = App.spritelist
else:
slist = App.getSpritesbyClass(sclass)
return list(filter(self.collidingWith, slist))
def destroy(self):
"""
Call the `ggame.Sprite.destroy` method to prevent the sprite from being displayed,
or checked in collision detection. If you only want to prevent a sprite from being
displayed, set the `ggame.Sprite.visible` attribute to `False`.
"""
App._remove(self)
self.GFX.destroy()
Ancestors (in MRO)
- Sprite
- builtins.object
Static methods
def __init__(
self, asset, pos=(0, 0), edgedef=None)
The Sprite
must be created with an existing graphical asset
.
An optional pos
or position may be provided, which specifies the
starting (x,y) coordinates of the sprite on the screen. By default,
the position of a sprite defines the location of its upper-left hand
corner. This behavior can be modified by customizing the center
of
the sprite.
An optional edgedef
or edge definition may be provided, which
specifies an asset that will be used to define the boundaries of
the sprite for the purpose of collision detection. If no edgedef
asset is given, the Sprite asset is used, which will be a rectangular
asset in the case of an image texture. This option is typically used
to define a visible image outline for a texture-based sprite that has
a transparent texture image background.
Example: player = Sprite(ImageAsset("player.png", (100,100), CircleAsset(50))
This creates a sprite using the player.png
image, positioned with its
upper left corner at coordinates (100,100) and with a 50 pixel radius
circular collision border.
def __init__(self, asset, pos=(0,0), edgedef=None):
"""
The `ggame.Sprite` must be created with an existing graphical `asset`.
An optional `pos` or position may be provided, which specifies the
starting (x,y) coordinates of the sprite on the screen. By default,
the position of a sprite defines the location of its upper-left hand
corner. This behavior can be modified by customizing the `center` of
the sprite.
An optional `edgedef` or edge definition may be provided, which
specifies an asset that will be used to define the boundaries of
the sprite for the purpose of collision detection. If no `edgedef`
asset is given, the Sprite asset is used, which will be a rectangular
asset in the case of an image texture. This option is typically used
to define a visible image outline for a texture-based sprite that has
a transparent texture image background.
Example: player = Sprite(ImageAsset("player.png", (100,100), CircleAsset(50))
This creates a sprite using the `player.png` image, positioned with its
upper left corner at coordinates (100,100) and with a 50 pixel radius
circular collision border.
"""
self._index = 0
if type(asset) == ImageAsset:
self.asset = asset
try:
#self.GFX = GFX_Sprite()
self.GFX = GFX_Sprite(asset.GFX) # GFX is PIXI Sprite
except:
self.GFX = None
elif type(asset) in [RectangleAsset,
CircleAsset,
EllipseAsset,
PolygonAsset,
LineAsset,
]:
self.asset = asset
self.GFX = GFX_Sprite(asset.GFX.generateTexture())
#self.GFX = asset.GFX.clone() # GFX is PIXI Graphics (from Sprite)
#self.GFX.visible = True
elif type(asset) in [TextAsset]:
self.asset = asset._clone()
self.GFX = self.asset.GFX # GFX is PIXI Text (from Sprite)
self.GFX.visible = True
if not edgedef:
self.edgedef = asset
else:
self.edgedef = edgedef
self.xmin = self.xmax = self.ymin = self.ymax = 0
self.position = pos
"""Tuple indicates the position of the sprite on the screen."""
self._extentsdirty = True
"""Boolean indicates if extents must be calculated before collision test"""
self._createBaseVertices()
self._setExtents()
"""Initialize the extents (xmax, xmin, etc.) for collision detection"""
App._add(self)
def circularCollisionModel(
self)
Obsolete. No op.
def circularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def collidingPolyWithPoly(
self, obj)
def collidingPolyWithPoly(self, obj):
return True
def collidingWith(
self, obj)
Return a boolean True if this sprite is currently overlapping the sprite
referenced by obj
. Returns False if checking for collision with
itself. Returns False if extents of object make it impossible for
collision to occur. Returns True if sprite's edgedef
parameter overlaps
with other sprite's edgedef
parameter, taking into consideration both
sprites' center, rotation and scale settings.
def collidingWith(self, obj):
"""
Return a boolean True if this sprite is currently overlapping the sprite
referenced by `obj`. Returns False if checking for collision with
itself. Returns False if extents of object make it impossible for
collision to occur. Returns True if sprite's `edgedef` parameter overlaps
with other sprite's `edgedef` parameter, taking into consideration both
sprites' center, rotation and scale settings.
"""
if self is obj:
return False
else:
self._setExtents()
obj._setExtents()
# Gross check for overlap will usually rule out a collision
if (self.xmin > obj.xmax
or self.xmax < obj.xmin
or self.ymin > obj.ymax
or self.ymax < obj.ymin):
return False
# Otherwise, perform a careful overlap determination
elif type(self.asset) is CircleAsset:
if type(obj.asset) is CircleAsset:
# two circles .. check distance between
sx = (self.xmin + self.xmax) / 2
sy = (self.ymin + self.ymax) / 2
ox = (obj.xmin + obj.xmax) / 2
oy = (obj.ymin + obj.ymax) / 2
d = math.sqrt((sx-ox)**2 + (sy-oy)**2)
return d <= self.width/2 + obj.width/2
else:
return self.collidingCircleWithPoly(self, obj)
else:
if type(obj.asset) is CircleAsset:
return self.collidingCircleWithPoly(obj, self)
else:
return self.collidingPolyWithPoly(obj)
def collidingWithSprites(
self, sclass=None)
Return a list of sprite objects identified by the sclass
parameter
that are currently colliding with (that is, with which the collidingWith
method returns True) this sprite. If sclass
is set to None
(default), then
all other sprites are checked for collision, otherwise, only sprites whose
class matches sclass
are checked.
def collidingWithSprites(self, sclass = None):
"""
Return a list of sprite objects identified by the `sclass` parameter
that are currently colliding with (that is, with which the `ggame.Sprite.collidingWith`
method returns True) this sprite. If `sclass` is set to `None` (default), then
all other sprites are checked for collision, otherwise, only sprites whose
class matches `sclass` are checked.
"""
if sclass is None:
slist = App.spritelist
else:
slist = App.getSpritesbyClass(sclass)
return list(filter(self.collidingWith, slist))
def destroy(
self)
Call the destroy
method to prevent the sprite from being displayed,
or checked in collision detection. If you only want to prevent a sprite from being
displayed, set the visible
attribute to False
.
def destroy(self):
"""
Call the `ggame.Sprite.destroy` method to prevent the sprite from being displayed,
or checked in collision detection. If you only want to prevent a sprite from being
displayed, set the `ggame.Sprite.visible` attribute to `False`.
"""
App._remove(self)
self.GFX.destroy()
def firstImage(
self)
Select and display the first image used by this sprite.
def firstImage(self):
"""
Select and display the *first* image used by this sprite.
"""
self.GFX.texture = self.asset[0]
def lastImage(
self)
Select and display the last image used by this sprite.
def lastImage(self):
"""
Select and display the *last* image used by this sprite.
"""
self.GFX.texture = self.asset[-1]
def nextImage(
self, wrap=False)
Select and display the next image used by this sprite. If the current image is already the last image, then the image is not advanced.
If the optional wrap
parameter is set to True
, then calling
nextImage
on the last image will cause the first
image to be loaded.
def nextImage(self, wrap = False):
"""
Select and display the *next* image used by this sprite.
If the current image is already the *last* image, then
the image is not advanced.
If the optional `wrap` parameter is set to `True`, then calling
`ggame.Sprite.nextImage` on the last image will cause the *first*
image to be loaded.
"""
self._index += 1
if self._index >= len(self.asset):
if wrap:
self._index = 0
else:
self._index = len(self.asset)-1
self.GFX.texture = self.asset[self._index]
def prevImage(
self, wrap=False)
Select and display the previous image used by this sprite. If the current image is already the first image, then the image is not changed.
If the optional wrap
parameter is set to True
, then calling
prevImage
on the first image will cause the last
image to be loaded.
def prevImage(self, wrap = False):
"""
Select and display the *previous* image used by this sprite.
If the current image is already the *first* image, then
the image is not changed.
If the optional `wrap` parameter is set to `True`, then calling
`ggame.Sprite.prevImage` on the first image will cause the *last*
image to be loaded.
"""
self._index -= 1
if self._index < 0:
if wrap:
self._index = len(self.asset)-1
else:
self._index = 0
self.GFX.texture = self.asset[self._index]
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def setImage(
self, index=0)
Select the image to display by giving its index
, where an index
of zero represents the first image in the asset.
This is equivalent to setting the index
property
directly.
def setImage(self, index=0):
"""
Select the image to display by giving its `index`, where an index
of zero represents the *first* image in the asset.
This is equivalent to setting the `ggame.Sprite.index` property
directly.
"""
self.index = index
Instance variables
var center
This attribute represents the horizontal and vertical position of the
sprite "center" as a tuple of floating point numbers. See the
descriptions for fxcenter
and fycenter
for
more details.
var fxcenter
This represents the horizontal position of the sprite "center", as a floating point number between 0.0 and 1.0. A value of 0.0 means that the x-coordinate of the sprite refers to its left hand edge. A value of 1.0 refers to its right hand edge. Any value in between may be specified. Values may be assigned to this attribute.
var fycenter
This represents the vertical position of the sprite "center", as a floating point number between 0.0 and 1.0. A value of 0.0 means that the x-coordinate of the sprite refers to its top edge. A value of 1.0 refers to its bottom edge. Any value in between may be specified. Values may be assigned to this attribute.
var height
This is an integer representing the display height of the sprite. Assigning a value to the height will scale the image vertically.
var index
This is an integer index in to the list of images available for this sprite.
var position
Tuple indicates the position of the sprite on the screen.
var rotation
This attribute may be used to change the rotation of the sprite on the screen. Value may be a floating point number. A value of 0.0 means no rotation. A value of 1.0 means a rotation of 1 radian in a counter-clockwise direction. One radian is 180/pi or approximately 57.3 degrees.
var scale
This attribute may be used to change the size of the sprite ('scale' it) on the screen. Value may be a floating point number. A value of 1.0 means that the sprite image will keep its original size. A value of 2.0 would double it, etc.
var visible
This boolean attribute may be used to change the visibility of the sprite. Setting
visible
to False
will prevent the sprite from rendering on the
screen.
var width
This is an integer representing the display width of the sprite. Assigning a value to the width will scale the image horizontally.
var x
This represents the x-coordinate of the sprite on the screen. Assigning a value to this attribute will move the sprite horizontally.
var y
This represents the y-coordinate of the sprite on the screen. Assigning a value to this attribute will move the sprite vertically.
Methods
def collidingCircleWithPoly(
cls, circ, poly)
@classmethod
def collidingCircleWithPoly(cls, circ, poly):
return True
class TextAsset
The TextAsset
is a "virtual" asset that is created on the fly
without requiring creation of an image file. A TextAsset
instance
represents a block of text, together with its styling (font, color, etc.).
class TextAsset(_GraphicsAsset):
"""
The `ggame.TextAsset` is a "virtual" asset that is created on the fly
without requiring creation of an image file. A `TextAsset` instance
represents a block of text, together with its styling (font, color, etc.).
"""
def __init__(self, text, **kwargs):
"""
The `ggame.TextAsset` must be created with a string as the `text` parameter.
The remaining optional arguments must be supplied as keyword parameters. These
parameters are described under the class attributes, below:
"""
super().__init__()
self.text = text
self.style = kwargs.get('style', '20px Arial')
"""A string that specifies style, size and typeface (e.g. `'italic 20pt Helvetica'` or `'20px Arial'`)"""
width = kwargs.get('width', 100)
"""Width of the text block on the screen, in pixels."""
self.fill = kwargs.get('fill', Color(0, 1))
"""A valid `ggame.Color` instance that specifies the color and transparency of the text."""
self.align = kwargs.get('align', 'left')
"""The alignment style of the text. One of: `'left'`, `'center'`, or `'right'`."""
self.GFX = GFX_Text(self.text,
{'font': self.style,
'fill' : self.fill.color,
'align' : self.align,
'wordWrap' : True,
'wordWrapWidth' : width,
})
"""The `GFX` property represents the underlying system object."""
self.GFX.alpha = self.fill.alpha
self.GFX.visible = False
def _clone(self):
return type(self)(self.text,
style = self.style,
width = self.width,
fill = self.fill,
align = self.align)
@property
def width(self):
return self.GFX.width
@property
def height(self):
return self.GFX.height
Ancestors (in MRO)
- TextAsset
- __pdoc_file_module__._GraphicsAsset
- __pdoc_file_module__._Asset
- builtins.object
Static methods
def __init__(
self, text, **kwargs)
The TextAsset
must be created with a string as the text
parameter.
The remaining optional arguments must be supplied as keyword parameters. These parameters are described under the class attributes, below:
def __init__(self, text, **kwargs):
"""
The `ggame.TextAsset` must be created with a string as the `text` parameter.
The remaining optional arguments must be supplied as keyword parameters. These
parameters are described under the class attributes, below:
"""
super().__init__()
self.text = text
self.style = kwargs.get('style', '20px Arial')
"""A string that specifies style, size and typeface (e.g. `'italic 20pt Helvetica'` or `'20px Arial'`)"""
width = kwargs.get('width', 100)
"""Width of the text block on the screen, in pixels."""
self.fill = kwargs.get('fill', Color(0, 1))
"""A valid `ggame.Color` instance that specifies the color and transparency of the text."""
self.align = kwargs.get('align', 'left')
"""The alignment style of the text. One of: `'left'`, `'center'`, or `'right'`."""
self.GFX = GFX_Text(self.text,
{'font': self.style,
'fill' : self.fill.color,
'align' : self.align,
'wordWrap' : True,
'wordWrapWidth' : width,
})
"""The `GFX` property represents the underlying system object."""
self.GFX.alpha = self.fill.alpha
self.GFX.visible = False
def destroy(
self)
def destroy(self):
if hasattr(self, 'GFX'):
try:
for gfx in self.GFXlist:
try:
gfx.destroy(True)
except:
pass
except:
pass
Instance variables
var GFX
The GFX
property represents the underlying system object.
var align
The alignment style of the text. One of: 'left'
, 'center'
, or 'right'
.
var height
var style
A string that specifies style, size and typeface (e.g. 'italic 20pt Helvetica'
or '20px Arial'
)
var text
var width