ggmath module
# ggmath - ggame extensions for geometry and mathematics in the browser
from ggame import Frame, Color, LineStyle, LineAsset, CircleAsset, Sprite, App
from ggame import TextAsset, ImageAsset, PolygonAsset, RectangleAsset
from abc import ABCMeta, abstractmethod
from operator import add
from collections import namedtuple
from math import sin, cos, sqrt, pi
from time import time
class _MathDynamic(metaclass=ABCMeta):
def __init__(self):
self._dynamic = False # not switched on, by default!
def destroy(self):
MathApp._removeDynamic(self)
def step(self):
pass
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def _setDynamic(self):
MathApp._addDynamic(self)
self._dynamic = True
class _MathVisual(Sprite, _MathDynamic, metaclass=ABCMeta):
posinputsdef = [] # a list of names (string) of required positional inputs
nonposinputsdef = [] # a list of names (string) of required non positional inputs
defaultsize = 15
defaultwidth = 200
defaultcolor = Color(0, 1)
defaultstyle = LineStyle(1, Color(0, 1))
def __init__(self, asset, *args, **kwargs):
"""
Required inputs
* **asset** a ggame asset
* **args** the list of required positional and nonpositional arguments,
as named in the posinputsdef and nonposinputsdef lists
* **kwargs** all other optional keyword arguments:
positioning - logical (default) or physical, size, width, color, style
movable
"""
MathApp._addVisual(self)
#Sprite.__init__(self, asset, args[0])
_MathDynamic.__init__(self)
self._movable = False
self._selectable = False
self._strokable = False
self.selected = False
self.mouseisdown = False
#
self.positioning = kwargs.get('positioning', 'logical')
# positional inputs
self.PI = namedtuple('PI', self.posinputsdef)
# nonpositional inputs
self.NPI = namedtuple('NPI', self.nonposinputsdef)
# standard inputs (not positional)
standardargs = ['size','width','color','style']
self.SI = namedtuple('SI', standardargs)
# correct number of args?
if len(args) != len(self.posinputsdef) + len(self.nonposinputsdef):
raise TypeError("Incorrect number of parameters provided")
self.args = args
# generated named tuple of functions from positional inputs
self.posinputs = self.PI(*[self.Eval(p) for p in args][:len(self.posinputsdef)])
self._getPhysicalInputs()
# first positional argument must be a sprite position!
Sprite.__init__(self, asset, self.pposinputs[0])
# generated named tuple of functions from nonpositional inputs
if len(self.nonposinputsdef) > 0:
self.nposinputs = self.NPI(*[self.Eval(p) for p in args][(-1*len(self.nonposinputsdef)):])
else:
self.nposinputs = []
self.stdinputs = self.SI(self.Eval(kwargs.get('size', self.defaultsize)),
self.Eval(kwargs.get('width', self.defaultwidth)),
self.Eval(kwargs.get('color', self.defaultcolor)),
self.Eval(kwargs.get('style', self.defaultstyle)))
self.sposinputs = self.PI(*[0]*len(self.posinputs))
self.spposinputs = self.PI(*self.pposinputs)
self.snposinputs = self.NPI(*[0]*len(self.nposinputs))
self.sstdinputs = self.SI(*[0]*len(self.stdinputs))
def step(self):
self._touchAsset()
def _saveInputs(self, inputs):
self.sposinputs, self.spposinputs, self.snposinputs, self.sstdinputs = inputs
def _getInputs(self):
self._getPhysicalInputs()
return (self.PI(*[p() for p in self.posinputs]),
self.PI(*self.pposinputs),
self.NPI(*[p() for p in self.nposinputs]),
self.SI(*[p() for p in self.stdinputs]))
def _getPhysicalInputs(self):
"""
Translate all positional inputs to physical
"""
pplist = []
if self.positioning == 'logical':
for p in self.posinputs:
pval = p()
try:
pp = MathApp.logicalToPhysical(pval)
except AttributeError:
pp = MathApp._scale * pval
pplist.append(pp)
else:
# already physical
pplist = [p() for p in self.posinputs]
self.pposinputs = self.PI(*pplist)
def _inputsChanged(self, saved):
return self.spposinputs != saved[1] or self.snposinputs != saved[2] or self.sstdinputs != saved[3]
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def _updateAsset(self, asset):
if type(asset) != ImageAsset:
visible = self.GFX.visible
if App._win != None:
App._win.remove(self.GFX)
self.GFX.destroy()
self.asset = asset
self.GFX = self.asset.GFX
self.GFX.visible = visible
if App._win != None:
App._win.add(self.GFX)
self.position = self.pposinputs.pos
@property
def movable(self):
return self._movable
@movable.setter
def movable(self, val):
if not self._dynamic:
self._movable = val
if val:
MathApp._addMovable(self)
else:
MathApp._removeMovable(self)
@property
def selectable(self):
return self._selectable
@selectable.setter
def selectable(self, val):
self._selectable = val
if val:
MathApp._addSelectable(self)
else:
MathApp._removeSelectable(self)
@property
def strokable(self):
return self._strokable
@strokable.setter
def strokable(self, val):
self._strokable = val
if val:
MathApp._addStrokable(self)
else:
MathApp._removeStrokable(self)
def select(self):
self.selected = True
def unselect(self):
self.selected = False
def mousedown(self):
self.mouseisdown = True
def mouseup(self):
self.mouseisdown = False
def processEvent(self, event):
pass
# define how your class responds to mouse clicks - returns True/False
@abstractmethod
def physicalPointTouching(self, ppos):
pass
# define how your class responds to being moved (physical units)
@abstractmethod
def translate(self, pdisp):
pass
# define how your class responds to being stroked (physical units)
def stroke(self, ppos, pdisp):
pass
# is the mousedown in a place that will result in a stroke?
def canstroke(self, ppos):
return False
def _touchAsset(self, force = False):
inputs = self._getInputs()
changed = self._inputsChanged(inputs)
if changed:
self._saveInputs(inputs)
if changed or force:
self._updateAsset(self._buildAsset())
@abstractmethod
def _buildAsset(self):
pass
class Label(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['text']
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of label
* **text** text contents of label
"""
super().__init__(TextAsset(""), *args, **kwargs)
self._touchAsset()
def _buildAsset(self):
return TextAsset(self.nposinputs.text(),
style="{0}px Courier".format(self.stdinputs.size()),
width=self.stdinputs.width(),
fill=self.stdinputs.color())
def __call__(self):
return self.nposinputs.text()
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
def translate(self, pdisp):
pass
class InputNumeric(Label):
def __init__(self, pos, val, **kwargs):
"""
Required Inputs
* **pos** position of button
* **val** initial value of input
Optional Keyword Input
* **fmt** a Python format string (default is {0.2})
"""
self._fmt = kwargs.get('fmt', '{0.2}')
self._val = self.Eval(val)() # initialize to simple numeric
self._savedval = self._val
self._updateText()
super().__init__(pos, self._textValue, **kwargs)
self.selectable = True
def _textValue(self):
return self._text()
def _updateText(self):
self._text = self.Eval(self._fmt.format(self._val))
def processEvent(self, event):
if event.key in "0123456789insertdelete":
key = event.key
if event.key == 'insert':
key = '-'
elif event.key == 'delete':
key = '.'
if self._text() == "0":
self._text = self.Eval("")
self._text = self.Eval(self._text() + key)
self._touchAsset()
elif event.key in ['enter','escape']:
if event.key == 'enter':
try:
self._val = float(self._text())
except ValueError:
self._val = self._savedval
self._savedval = self._val
self.unselect()
def select(self):
super().select()
self._savedval = self._val
self._val = 0
self._updateText()
self._touchAsset()
MathApp.listenKeyEvent("keypress", "*", self.processEvent)
def unselect(self):
super().unselect()
self._val = self._savedval
self._updateText()
self._touchAsset()
try:
MathApp.unlistenKeyEvent("keypress", "*", self.processEvent)
except ValueError:
pass
def __call__(self):
return self._val
class InputButton(Label):
def __init__(self, callback, *args, **kwargs):
"""
Required Inputs
* **pos** position of button
* **text** text of button
* **callback** reference of a function to execute, passing this button object
"""
super().__init__(*args, **kwargs)
self._touchAsset()
self._callback = callback
self.selectable = True
def _buildAsset(self):
return TextAsset(self.nposinputs.text(),
style="bold {0}px Courier".format(self.stdinputs.size()),
width=self.stdinputs.width(),
fill=self.stdinputs.color())
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
def unselect(self):
super().unselect()
class _Point(_MathVisual, metaclass=ABCMeta):
posinputsdef = ['pos']
nonposinputsdef = []
def __init__(self, asset, *args, **kwargs):
"""
Required Inputs
* **asset** asset object to use
* **pos** position of point
"""
super().__init__(asset, *args, **kwargs)
self._touchAsset()
self.center = (0.5, 0.5)
def __call__(self):
return self.posinputs.pos()
def step(self):
pass # FIXME
self._touchAsset()
def physicalPointTouching(self, ppos):
return MathApp.distance(ppos, self.pposinputs.pos) < self.sstdinputs.size
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
class Point(_Point):
defaultsize = 5
defaultstyle = LineStyle(0, Color(0, 1))
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of point
"""
super().__init__(CircleAsset(self.defaultsize,
self.defaultstyle, self.defaultcolor), *args, **kwargs)
def _buildAsset(self):
return CircleAsset(self.stdinputs.size(),
self.stdinputs.style(),
self.stdinputs.color())
class ImagePoint(_Point):
def __init__(self, url, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
frame = kwargs.get('frame', None)
qty = kwargs.get('qty', 1)
direction = kwargs.get('direction', 'horizontal')
margin = kwargs.get('margin', 0)
self._imageasset = ImageAsset(url, frame, qty, direction, margin)
super().__init__(self._imageasset, *args, **kwargs)
def _buildAsset(self):
return self._imageasset
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
class InputImageButton(ImagePoint):
def __init__(self, url, callback, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **callback** reference of a function to execute, passing this button object
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
super().__init__(url, *args, **kwargs)
self.center = (0,0)
self._callback = callback
self.selectable = True
self.firstImage()
self.mousewasdown = self.mouseisdown
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
def unselect(self):
super().unselect()
def __call__(self):
# code for controlling the button image state only works if the
# button state is being monitored!
if self.mouseisdown != self.mousewasdown:
if self.mouseisdown:
self.nextImage()
else:
self.firstImage()
self.mousewasdown = self.mouseisdown
return self.mouseisdown
class InputImageToggle(ImagePoint):
def __init__(self, url, statelist, initindex, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **statelist** list of values to correspond with toggle states
* **initindex** index to initial toggle state
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **direction** for sprite sheet one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
* Note the qty of images is equal to length of the statelist
"""
self.statelist = statelist
kwargs.setdefault('qty', len(statelist))
super().__init__(url, *args, **kwargs)
self.center = (0,0)
self.selectable = True
self.togglestate = initindex
self.setImage(self.togglestate)
def select(self):
super().select()
self.togglestate += 1
if self.togglestate == len(self.statelist):
self.togglestate = 0
self.setImage(self.togglestate)
self.unselect()
def __call__(self):
return self.statelist[self.togglestate]
class MetalToggle(InputImageToggle):
def __init__(self, initindex, *args, **kwargs):
"""
Required Inputs
* **initindex** index to initial toggle state
* **pos** position of toggle
"""
kwargs.setdefault('frame', Frame(0,0,110,150))
super().__init__("toggle-up-down.png", [True, False], initindex, *args, **kwargs)
self.scale = 0.4
class GlassButton(InputImageButton):
def __init__(self, callback, *args, **kwargs):
"""
Required Inputs
* **callback** reference of a function to execute, passing this button object
* **pos** position of point
"""
kwargs.setdefault('frame', Frame(0,0,100,100))
kwargs.setdefault('qty', 2)
super().__init__("button-round.png", callback, *args, **kwargs)
self.scale = 0.3
class ImageIndicator(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['value']
def __init__(self, url, *args, **kwargs):
"""
Required Inputs
* **url** location of image file consisting of two image sprite sheet
* **pos** position of point
* **value** state of the indicator (True/False or integer)
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
kwargs.setdefault('frame', None)
kwargs.setdefault('qty', 1)
kwargs.setdefault('direction', 'horizontal')
kwargs.setdefault('margin', 0)
super().__init__(
ImageAsset(url,
kwargs['frame'],
kwargs['qty'],
kwargs['direction'],
kwargs['margin']),
*args, **kwargs)
self.center = (0,0)
def _buildAsset(self):
inval = self.nposinputs.value()
if inval == True:
self.setImage(1)
elif inval == False:
self.setImage(0)
else:
self.setImage(inval)
return self.asset
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
def translate(self, pdisp):
pass
class LEDIndicator(ImageIndicator):
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of point
* **value** state of the indicator (True/False or integer)
"""
kwargs.setdefault('frame', Frame(0,0,600,600))
kwargs.setdefault('qty', 2)
super().__init__("red-led-off-on.png", *args, **kwargs)
self.scale = 0.05
class LineSegment(_MathVisual):
posinputsdef = ['pos','end']
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** start position of segment
* **end** end position of segment
Optional Inputs
* **style** line style (thickness, color)
"""
super().__init__(LineAsset(0,0, self.defaultstyle), *args, **kwargs)
self._touchAsset()
def _buildAsset(self):
start = self.pposinputs.pos
end = self.pposinputs.end
self.position = start
return LineAsset(end[0]-start[0],
end[1]-start[1],
self.stdinputs.style())
def physicalPointTouching(self, ppos):
return False
def translate(self, pdisp):
pass
class Circle(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['radius']
defaultcolor = Color(0,0)
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** center of circle
* **radius** radius of circle (logical) or point on circle
Optional Inputs
* **style** border line style (thickness, color)
* **color** fill color
"""
"""
Radius may be scalar or point
"""
super().__init__(CircleAsset(0, self.defaultstyle, self.defaultcolor), *args, **kwargs)
self._touchAsset()
self.fxcenter = self.fycenter = 0.5
def _buildAsset(self):
pcenter = self.spposinputs.pos
try:
pradius = MathApp.distance(self.posinputs.pos(), self.nposinputs.radius()) * MathApp._scale
except (AttributeError, TypeError):
pradius = self.nposinputs.radius() * MathApp._scale
style = self.stdinputs.style()
fill = self.stdinputs.color()
ymax = pcenter[1]+pradius
ymin = pcenter[1]-pradius
xmax = pcenter[0]+pradius
xmin = pcenter[0]-pradius
try:
if ymin > MathApp.height or ymax < 0 or xmax < 0 or xmin > MathApp.width:
return CircleAsset(pradius, style, fill)
elif pradius > 2*MathApp.width:
# here begins unpleasant hack to overcome crappy circles
poly = self._buildPolygon(pcenter, pradius)
if len(poly):
passet = PolygonAsset(poly, style, fill)
return passet
except AttributeError:
return CircleAsset(pradius, style, fill)
return CircleAsset(pradius, style, fill)
def _buildPolygon(self, pcenter, pradius):
"""
pcenter is in screen relative coordinates.
returns a coordinate list in circle relative coordinates
"""
xcepts = [self._findIntercepts(pcenter, pradius, 0,0,0,MathApp.height),
self._findIntercepts(pcenter, pradius, 0,0,MathApp.width,0),
self._findIntercepts(pcenter, pradius, MathApp.width,0,MathApp.width,MathApp.height),
self._findIntercepts(pcenter, pradius, 0,MathApp.height, MathApp.width, MathApp.height)]
ilist = []
for x in xcepts:
if x and len(x) < 2:
ilist.extend(x)
#ilist is a list of boundary intercepts that are screen-relative
if len(ilist) > 1:
xrange = ilist[-1][0] - ilist[0][0]
yrange = ilist[-1][1] - ilist[0][1]
numpoints = 20
inx = 0
for i in range(numpoints):
icepts = self._findIntercepts(pcenter, pradius,
pcenter[0], pcenter[1],
ilist[0][0] + xrange*(i+1)/(numpoints+1),
ilist[0][1] + yrange*(i+1)/(numpoints+1))
if len(icepts):
ilist.insert(inx+1, icepts[0])
inx = inx + 1
self._addBoundaryVertices(ilist, pcenter, pradius)
ilist.append(ilist[0])
ilist = [(i[0] - pcenter[0], i[1] - pcenter[1]) for i in ilist]
return ilist
def _addBoundaryVertices(self, plist, pcenter, pradius):
"""
Sides 0=top, 1=right, 2=bottom, 3=left
"""
#figure out rotation in point sequence
cw = 0
try:
rtst = plist[0:3]+[plist[0]]
for p in range(3):
cw = cw + (rtst[p+1][0]-rtst[p][0])*(rtst[p+1][1]+rtst[p][1])
except IndexError:
#print(plist)
return
cw = self._sgn(cw)
cw = 1 if cw < 0 else 0
vertices = ((-100,-100),
(MathApp.width+100,-100),
(MathApp.width+100,MathApp.height+100),
(-100,MathApp.height+100))
nextvertex = [(vertices[0],vertices[1]),
(vertices[1],vertices[2]),
(vertices[2],vertices[3]),
(vertices[3],vertices[0])]
nextsides = [(3,1),(0,2),(1,3),(2,0)]
edges = ((None,0),(MathApp.width,None),(None,MathApp.height),(0,None))
endside = startside = None
for side in range(4):
if endside is None and (edges[side][0] == round(plist[-1][0]) or edges[side][1] == round(plist[-1][1])):
endside = side
if startside is None and (edges[side][0] == round(plist[0][0]) or edges[side][1] == round(plist[0][1])):
startside = side
iterations = 0
while startside != endside:
iterations = iterations + 1
if iterations > 20:
break
if endside != None and startside != None: # and endside != startside
plist.append(nextvertex[endside][cw])
endside = nextsides[endside][cw]
def _sgn(self, x):
return 1 if x >= 0 else -1
def _findIntercepts(self, c, r, x1, y1, x2, y2):
"""
c (center) and x and y values are physical, screen relative.
function returns coordinates in screen relative format
"""
x1n = x1 - c[0]
x2n = x2 - c[0]
y1n = y1 - c[1]
y2n = y2 - c[1]
dx = x2n-x1n
dy = y2n-y1n
dr = sqrt(dx*dx + dy*dy)
D = x1n*y2n - x2n*y1n
disc = r*r*dr*dr - D*D
dr2 = dr*dr
if disc <= 0: # less than two solutions
return []
sdisc = sqrt(disc)
x = [(D*dy + self._sgn(dy)*dx*sdisc)/dr2 + c[0], (D*dy - self._sgn(dy)*dx*sdisc)/dr2 + c[0]]
y = [(-D*dx + abs(dy)*sdisc)/dr2 + c[1], (-D*dx - abs(dy)*sdisc)/dr2 + c[1]]
getcoords = lambda x, y, c: [(x,y)] if x>=0 and x<=MathApp.width and y>=0 and y<=MathApp.height else []
res = getcoords(x[0], y[0], c)
res.extend(getcoords(x[1], y[1], c))
return res
@property
def center(self):
return self._center()
@center.setter
def center(self, val):
newval = self.Eval(val)
if newval != self._center:
self._center = newval
self._touchAsset()
@property
def radius(self):
return self._radius()
@radius.setter
def radius(self, val):
newval = self.Eval(val)
if newval != self._radius:
self._radius = newval
self._touchAsset()
def step(self):
self._touchAsset()
def physicalPointTouching(self, ppos):
r = MathApp.distance(self._pcenter, ppos)
inner = self._pradius - self.style.width/2
outer = self._pradius + self.style.width/2
return r <= outer and r >= inner
def translate(self, pdisp):
pass
class Slider(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['minval','maxval','initial']
def __init__(self, *args, **kwargs):
super().__init__(
RectangleAsset(1, 1), *args, **kwargs)
self._val = self.nposinputs.initial()
self._steps = kwargs.get('steps', 50)
self._step = (self.nposinputs.maxval()-self.nposinputs.minval())/self._steps
self._leftctrl = kwargs.get('leftkey', None)
self._rightctrl = kwargs.get('rightkey', None)
self._centerctrl = kwargs.get('centerkey', None)
self.selectable = True # must be after super init!
self.strokable = True # this enables grabbing/slideing the thumb
self.thumbcaptured = False
self._thumbwidth = max(self.stdinputs.width()/40, 1)
self.thumb = Sprite(RectangleAsset(self._thumbwidth,
self.stdinputs.size()-2, LineStyle(1, self.stdinputs.color()), self.stdinputs.color()),
self.thumbXY())
self._touchAsset()
if self._leftctrl:
MathApp.listenKeyEvent("keydown", self._leftctrl, self.moveLeft)
if self._rightctrl:
MathApp.listenKeyEvent("keydown", self._rightctrl, self.moveRight)
if self._centerctrl:
MathApp.listenKeyEvent("keydown", self._centerctrl, self.moveCenter)
def thumbXY(self):
minval = self.nposinputs.minval()
maxval = self.nposinputs.maxval()
return (self.spposinputs.pos[0]+(self._val-minval)*
(self.sstdinputs.width-self._thumbwidth)/(maxval-minval),
self.spposinputs.pos[1]+1)
def __call__(self):
return self._val
@property
def value(self):
return self._val
@value.setter
def value(self, val):
self._setval(val)
def _buildAsset(self):
self.setThumb()
return RectangleAsset(
self.stdinputs.width(), self.stdinputs.size(),
line=self.stdinputs.style(), fill=Color(0,0))
def setThumb(self):
self.thumb.position = self.thumbXY()
def step(self):
pass
def _setval(self, val):
minval = self.nposinputs.minval()
maxval = self.nposinputs.maxval()
if val <= minval:
self._val = minval
elif val >= maxval:
self._val = maxval
else:
self._val = round((val - minval)*self._steps/(maxval-minval))*self._step + minval
self.setThumb()
def increment(self, step):
self._setval(self._val + step)
def select(self):
super().select()
if not self._leftctrl:
MathApp.listenKeyEvent("keydown", "left arrow", self.moveLeft)
if not self._rightctrl:
MathApp.listenKeyEvent("keydown", "right arrow", self.moveRight)
MathApp.listenMouseEvent("click", self.mouseClick)
def unselect(self):
super().unselect()
try:
if not self._leftctrl:
MathApp.unlistenKeyEvent("keydown", "left arrow", self.moveLeft)
if not self._rightctrl:
MathApp.unlistenKeyEvent("keydown", "right arrow", self.moveRight)
MathApp.unlistenMouseEvent("click", self.mouseClick)
except ValueError:
pass
def mouseClick(self, event):
if self.physicalPointTouching((event.x, event.y)):
if event.x > self.thumb.x + self._thumbwidth:
self.moveRight(event)
elif event.x < self.thumb.x:
self.moveLeft(event)
def moveLeft(self, event):
self.increment(-self._step)
def moveRight(self, event):
self.increment(self._step)
def moveCenter(self, event):
self._val = (self.snposinputs.minval + self.snposinputs.maxval)/2
self.setThumb()
def canstroke(self, ppos):
return self.physicalPointTouchingThumb(ppos)
def stroke(self, ppos, pdisp):
_ppos = self.spposinputs.pos
minval = self.snposinputs.minval
maxval = self.snposinputs.maxval
xpos = ppos[0] + pdisp[0]
self.value = (xpos - _ppos[0])*(maxval-minval)/self.sstdinputs.width + minval
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
def physicalPointTouchingThumb(self, ppos):
thumbpos = self.thumbXY()
return (ppos[0] >= thumbpos[0] and
ppos[0] <= thumbpos[0] + self._thumbwidth + 2 and
ppos[1] >= thumbpos[1] and
ppos[1] <= thumbpos[1] + self.sstdinputs.size - 2)
def translate(self, pdisp):
pass
class Timer(_MathDynamic):
def __init__(self):
super().__init__()
self.once = []
self.callbacks = {}
self.reset()
self.step()
self._start = self._reset #first time
self.next = None
MathApp._addDynamic(self) # always dynamically defined
def reset(self):
self._reset = MathApp.time
def step(self):
nexttimers = []
calllist = []
self.time = MathApp.time - self._reset
while self.once and self.once[0][0] <= MathApp.time:
tickinfo = self.once.pop(0)
if tickinfo[1]: # periodic?
nexttimers.append((tickinfo[1], self.callbacks[tickinfo][0])) # delay, callback
calllist.append(self.callbacks[tickinfo].pop(0)) # remove callback and queue it
if not self.callbacks[tickinfo]: # if the callback list is empty
del self.callbacks[tickinfo] # remove the dictionary entry altogether
for tickadd in nexttimers:
self.callAfter(tickadd[0], tickadd[1], True) # keep it going
for call in calllist:
call(self)
def callAfter(self, delay, callback, periodic=False):
key = (MathApp.time + delay, delay if periodic else 0)
self.once.append(key)
callbacklist = self.callbacks.get(key, [])
callbacklist.append(callback)
self.callbacks[key] = callbacklist
self.once.sort()
def callAt(self, time, callback):
self.callAfter(time-self.time, callback)
def callEvery(self, period, callback):
self.callAfter(period, callback, True)
def __call__(self):
return self.time
class Bunny():
"""Bunny class is similar to turtle. Needs refinement.
Example use:
b = Bunny()
b.PenDown()
for i in range(100):
b.Right(1.5)
b.Move(i/25)
"""
def __init__ (self):
self.GoTo(0,0)
self.Color(0)
self.PenUp()
self.SetAngle(0)
def PenUp(self):
self.down = False
def PenDown(self):
self.down = True
def Color(self, color):
self.color = Color(color,1)
def GoTo(self, x, y):
self.pos = (x,y)
def SetAngle(self, a):
self.angle = a
def Right(self, da):
self.angle = self.angle - da
def Left(self, da):
self.angle = self.angle + da
def Move(self, d):
next = (self.pos[0] + d*cos(self.angle), self.pos[1] + d*sin(self.angle))
LineSegment(Point(self.pos, 0), Point(next, 0), LineStyle(1, self.color))
self.pos = next
#def physicalPointTouching(self, ppos):
# return MathApp.distance(ppos, self._ppos) < self._size
#def translate(self, pdisp):
# ldisp = MathApp.translatePhysicalToLogical(pdisp)
# pos = self._pos()
# self._pos = self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1]))
# self._touchAsset()
class MathApp(App):
_scale = 200 # pixels per unit
_xcenter = 0 # center of screen in units
_ycenter = 0
_mathVisualList = [] #
_mathDynamicList = []
_mathMovableList = []
_mathSelectableList = []
_mathStrokableList = []
_viewNotificationList = []
time = time()
def __init__(self, scale=_scale):
super().__init__()
MathApp.width = self.width
MathApp.height = self.height
MathApp._scale = scale # pixels per unit
# register event callbacks
self.listenMouseEvent("click", self.handleMouseClick)
self.listenMouseEvent("mousedown", self.handleMouseDown)
self.listenMouseEvent("mouseup", self.handleMouseUp)
self.listenMouseEvent("mousemove", self.handleMouseMove)
self.listenMouseEvent("wheel", self.handleMouseWheel)
self.mouseDown = False
self.mouseCapturedObject = None
self.mouseStrokedObject = None
self.mouseDownObject = None
self.mouseX = self.mouseY = None
self._touchAllVisuals()
self.selectedObj = None
MathApp.time = time()
def step(self):
MathApp.time = time()
for spr in self._mathDynamicList:
spr.step()
def _touchAllVisuals(self):
# touch all visual object assets to use scaling
for obj in self._mathVisualList:
obj._touchAsset(True)
@classmethod
def logicalToPhysical(cls, lp):
xxform = lambda xvalue, xscale, xcenter, physwidth: int((xvalue-xcenter)*xscale + physwidth/2)
yxform = lambda yvalue, yscale, ycenter, physheight: int(physheight/2 - (yvalue-ycenter)*yscale)
try:
return (xxform(lp[0], cls._scale, cls._xcenter, cls._win.width),
yxform(lp[1], cls._scale, cls._ycenter, cls._win.height))
except AttributeError:
return lp
@classmethod
def physicalToLogical(cls, pp):
xxform = lambda xvalue, xscale, xcenter, physwidth: (xvalue - physwidth/2)/xscale + xcenter
yxform = lambda yvalue, yscale, ycenter, physheight: (physheight/2 - yvalue)/yscale + ycenter
try:
return (xxform(pp[0], cls._scale, cls._xcenter, cls._win.width),
yxform(pp[1], cls._scale, cls._ycenter, cls._win.height))
except AttributeError:
return pp
@classmethod
def translatePhysicalToLogical(cls, pp):
xxform = lambda xvalue, xscale: xvalue/xscale
yxform = lambda yvalue, yscale: -yvalue/yscale
try:
return (xxform(pp[0], cls._scale), yxform(pp[1], cls._scale))
except AttributeError:
return pp
@classmethod
def translateLogicalToPhysical(cls, pp):
xxform = lambda xvalue, xscale: xvalue*xscale
yxform = lambda yvalue, yscale: -yvalue*yscale
try:
return (xxform(pp[0], cls._scale), yxform(pp[1], cls._scale))
except AttributeError:
return pp
def handleMouseClick(self, event):
found = False
for obj in self._mathSelectableList:
if obj.physicalPointTouching((event.x, event.y)):
found = True
if not obj.selected:
obj.select()
self.selectedObj = obj
if not found and self.selectedObj:
self.selectedObj.unselect()
self.selectedObj = None
def handleMouseDown(self, event):
self.mouseDown = True
self.mouseCapturedObject = None
self.mouseStrokedObject = None
for obj in self._mathSelectableList:
if obj.physicalPointTouching((event.x, event.y)):
obj.mousedown()
self.mouseDownObject = obj
break
for obj in self._mathMovableList:
if obj.physicalPointTouching((event.x, event.y)) and not (obj.strokable and obj.canstroke((event.x,event.y))):
self.mouseCapturedObject = obj
break
if not self.mouseCapturedObject:
for obj in self._mathStrokableList:
if obj.canstroke((event.x, event.y)):
self.mouseStrokedObject = obj
break
def handleMouseUp(self, event):
if self.mouseDownObject:
self.mouseDownObject.mouseup()
self.mouseDownObject = None
self.mouseDown = False
self.mouseCapturedObject = None
self.mouseStrokedObject = None
def handleMouseMove(self, event):
if not self.mouseX:
self.mouseX = event.x
self.mouseY = event.y
dx = event.x - self.mouseX
dy = event.y - self.mouseY
self.mouseX = event.x
self.mouseY = event.y
if self.mouseDown:
if self.mouseCapturedObject:
self.mouseCapturedObject.translate((dx, dy))
elif self.mouseStrokedObject:
self.mouseStrokedObject.stroke((self.mouseX,self.mouseY), (dx,dy))
else:
lmove = self.translatePhysicalToLogical((dx, dy))
MathApp._xcenter -= lmove[0]
MathApp._ycenter -= lmove[1]
self._touchAllVisuals()
self._viewNotify("translate")
@property
def viewPosition(self):
return (MathApp._xcenter, MathApp._ycenter)
@viewPosition.setter
def viewPosition(self, pos):
MathApp._xcenter, MathApp._ycenter = pos
self._touchAllVisuals()
self._viewNotify("translate")
def handleMouseWheel(self, event):
zoomfactor = event.wheelDelta/100
zoomfactor = 1+zoomfactor if zoomfactor > 0 else 1+zoomfactor
if zoomfactor > 1.2:
zoomfactor = 1.2
elif zoomfactor < 0.8:
zoomfactor = 0.8
MathApp._scale *= zoomfactor
self._touchAllVisuals()
self._viewNotify("zoom")
@classmethod
def addViewNotification(cls, handler):
cls._viewNotificationList.append(handler)
@classmethod
def removeViewNotification(cls, handler):
cls._viewNotificationList.remove(handler)
def _viewNotify(self, viewchange):
for handler in self._viewNotificationList:
handler(viewchange = viewchange, scale = self._scale, center = (self._xcenter, self._ycenter))
@classmethod
def distance(cls, pos1, pos2):
return sqrt((pos2[0]-pos1[0])**2 + (pos2[1]-pos1[1])**2)
@property
def scale(self):
return self._scale
@property
def width(cls):
return App._win.width
@classmethod
def _addVisual(cls, obj):
""" FIX ME """
if isinstance(obj, _MathVisual):
cls._mathVisualList.append(obj)
@classmethod
def _removeVisual(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathVisualList:
cls._mathVisualList.remove(obj)
@classmethod
def _addDynamic(cls, obj):
if isinstance(obj, _MathDynamic) and not obj in cls._mathDynamicList:
cls._mathDynamicList.append(obj)
@classmethod
def _removeDynamic(cls, obj):
if isinstance(obj, _MathDynamic) and obj in cls._mathDynamicList:
cls._mathDynamicList.remove(obj)
@classmethod
def _addMovable(cls, obj):
if isinstance(obj, _MathVisual) and not obj in cls._mathMovableList:
cls._mathMovableList.append(obj)
@classmethod
def _removeMovable(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathMovableList:
cls._mathMovableList.remove(obj)
@classmethod
def _addSelectable(cls, obj):
if isinstance(obj, _MathVisual) and not obj in cls._mathSelectableList:
cls._mathSelectableList.append(obj)
@classmethod
def _removeSelectable(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathSelectableList:
cls._mathSelectableList.remove(obj)
@classmethod
def _addStrokable(cls, obj):
if isinstance(obj, _MathVisual) and not obj in cls._mathStrokableList:
cls._mathStrokableList.append(obj)
@classmethod
def _removeStrokable(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathStrokableList:
cls._mathStrokableList.remove(obj)
@classmethod
def _destroy(cls, *args):
"""
This will clean up any class level storage.
"""
App._destroy(*args) # hit the App class first
MathApp._mathVisualList = []
MathApp._mathDynamicList = []
MathApp._mathMovableList = []
MathApp._mathSelectableList = []
MathApp._mathStrokableList = []
MathApp._viewNotificationList = []
# test code here
if __name__ == "__main__":
"""
index = 0
coordlist = [(1,1), (2,1), (2,0), (1,2), (1,1)]
def nextcoord():
global index
if index == len(coordlist):
index = 0
retval = coordlist[index]
index = index + 1
return retval
def one(t):
print("one")
def two(t):
print("two")
def three(t):
t.callAt(10, ten)
print("three")
def ten(t):
print("ten")
def tick(t):
print("tick")
#pm1 = PointMass((0.1,0))
def rotate(timer):
ip1.rotation += 0.01
#p1 = Point((0,0))
#p1.movable = True
#c1 = Circle(p1, 1.5, LineStyle(3, Color(0x0000ff,1)), Color(0x0000ff,0.3))
#s1 = Slider((200, 400), 0, 10, 2, positioning='physical',
# leftkey="a", rightkey="d", centerkey="s")
#p2 = Point((2,0))
#p2.movable = True
#p3 = Point((3,0))
#t = Timer()
#p4 = Point(lambda :(3, (int(t.time*100) % 400)/100))
#p5 = Point(lambda :nextcoord())
#ip1 = ImagePoint((0.1,0), 'bunny.png')
#LineSegment(p1,p4)
#l1 = Label((-4,2), lambda: "Elapsed Time: {0:.0}".format(t.time), size=20, width=400, positioning="logical")
#i1 = InputNumeric((200,300), 99.9, size=20, positioning="physical")
#l2 = Label((-4,1), lambda: "{0}".format(i1()), size=20)
#l3 = Label((-4,1), lambda: "{0:4.2f}".format(s1()), size=20)
#b1 = InputButton((200,350), "RESET", lambda: t.reset(), size=20, positioning="physical")
#t.callAfter(1, one)
#t.callAfter(2, two)
#t.callAfter(3, three)
#t.callAt(10, ten)
#t.callEvery(1, tick)
#t.callEvery(0.1, rotate)
def step(t):
global vx, vy, x, y
fx = 0
fy = mass * g
ax = thrust()*cos(sat.rotation)
ay = fy / mass + thrust()*sin(sat.rotation)
x = x + vx * tick + 0.5 * ax * tick**2
y = y + vy * tick + 0.5 * ay * tick**2
vx = vx + ax*tick
vy = vy + ay*tick
if y < 0:
y = 0
vy = 0
vslider.value = vy
def velocitytext():
return "Velocity: ({0:2.4},{1:2.4})".format(vx,vy)
def getposition():
return (x,y)
def turnleft(event):
sat.rotation += 0.01
def turnright(event):
sat.rotation -= 0.01
tick = 0.02
x = 0
y = 100
vx = vy = 0
mass = 1
g = -9.81
sat = Rocket(getposition)
sat.rotation = pi/2
sat.scale = 0.1
MathApp.listenKeyEvent('keydown', 'left arrow', turnleft)
MathApp.listenKeyEvent('keydown', 'right arrow', turnright)
thrust = Slider((100, 100), -50, 50, 0, positioning='physical', steps=200,
leftkey="down arrow", rightkey="up arrow", centerkey="space")
vslider = Slider((100, 125), -50, 50, 0, positioning='physical')
Label((100,150), velocitytext, size=15, positioning="physical")
#westp = Point((-100000,0))
#eastp = Point((100000,0))
#ground = LineSegment(westp, eastp)
#MathApp.addViewNotification(zoomCheck)
"""
def step(timer):
print(id(timer))
def labelcoords():
return (100 + vslider1(), 175)
def buttoncoords():
return (300 + vslider1(), 175)
def labelcolor():
colorval = vslider1()
return Color(colorval*256,1)
def pressbutton(caller):
print("button pressed: ", caller)
vslider1 = Slider((100, 150), 0, 250, 125, positioning='physical', steps=10)
def buttonstatus():
return "True" if imgbutton() else "False"
imgbutton = InputImageButton("button-round.png", pressbutton, (0,0), frame=Frame(0,0,100,100), qty=2)
imgbutton.scale = 0.5
label = Label(labelcoords, buttonstatus, size=15, positioning="physical", color=labelcolor)
button = InputButton(pressbutton, buttoncoords, "Press Me", size=15, positioning="physical")
numinput = InputNumeric((300, 275), 3.14, positioning="physical")
ip = ImagePoint( 'bunny.png', (0,0))
ip.movable = True
p1 = Point((0,0), color=Color(0x008000, 1))
p1.movable = True
p2 = Point((0,-1))
p3 = Point((1.2,0))
LineSegment(p2,p3, style=LineStyle(3, Color(0,1)))
LineSegment(p2,p1, style=LineStyle(3, Color(0,1)))
c2 = Circle((-1,-1), p1)
ii = ImageIndicator("red-led-off-on.png", (300,500), imgbutton, positioning="physical", frame=Frame(0,0,600,600), qty=2)
ii.scale = 0.1
glassbutton = GlassButton(None, (0,-0.5))
toggle = MetalToggle(0, (0, -1))
Li = LEDIndicator((300,450), glassbutton, positioning="physical")
Lit = LEDIndicator((300,480), toggle, positioning="physical")
def zoomCheck(**kwargs):
viewtype = kwargs.get('viewchange')
scale = kwargs.get('scale')
print(ap.scale)
#pcenter = Point((0, -5000000))
# c1 = Circle((0,-5000000), 5000000, LineStyle(1, Color(0x008040,1)), Color(0x008400,0.5))
ap = MathApp()
#ap.addViewNotification(zoomCheck)
ap.run()
"""
"""
Module variables
var pi
Classes
class Bunny
Bunny class is similar to turtle. Needs refinement.
Example use:
b = Bunny()
b.PenDown()
for i in range(100):
b.Right(1.5)
b.Move(i/25)
class Bunny():
"""Bunny class is similar to turtle. Needs refinement.
Example use:
b = Bunny()
b.PenDown()
for i in range(100):
b.Right(1.5)
b.Move(i/25)
"""
def __init__ (self):
self.GoTo(0,0)
self.Color(0)
self.PenUp()
self.SetAngle(0)
def PenUp(self):
self.down = False
def PenDown(self):
self.down = True
def Color(self, color):
self.color = Color(color,1)
def GoTo(self, x, y):
self.pos = (x,y)
def SetAngle(self, a):
self.angle = a
def Right(self, da):
self.angle = self.angle - da
def Left(self, da):
self.angle = self.angle + da
def Move(self, d):
next = (self.pos[0] + d*cos(self.angle), self.pos[1] + d*sin(self.angle))
LineSegment(Point(self.pos, 0), Point(next, 0), LineStyle(1, self.color))
self.pos = next
Ancestors (in MRO)
- Bunny
- builtins.object
Static methods
def __init__(
self)
def __init__ (self):
self.GoTo(0,0)
self.Color(0)
self.PenUp()
self.SetAngle(0)
def Color(
self, color)
def Color(self, color):
self.color = Color(color,1)
def GoTo(
self, x, y)
def GoTo(self, x, y):
self.pos = (x,y)
def Left(
self, da)
def Left(self, da):
self.angle = self.angle + da
def Move(
self, d)
def Move(self, d):
next = (self.pos[0] + d*cos(self.angle), self.pos[1] + d*sin(self.angle))
LineSegment(Point(self.pos, 0), Point(next, 0), LineStyle(1, self.color))
self.pos = next
def PenDown(
self)
def PenDown(self):
self.down = True
def PenUp(
self)
def PenUp(self):
self.down = False
def Right(
self, da)
def Right(self, da):
self.angle = self.angle - da
def SetAngle(
self, a)
def SetAngle(self, a):
self.angle = a
class Circle
class Circle(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['radius']
defaultcolor = Color(0,0)
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** center of circle
* **radius** radius of circle (logical) or point on circle
Optional Inputs
* **style** border line style (thickness, color)
* **color** fill color
"""
"""
Radius may be scalar or point
"""
super().__init__(CircleAsset(0, self.defaultstyle, self.defaultcolor), *args, **kwargs)
self._touchAsset()
self.fxcenter = self.fycenter = 0.5
def _buildAsset(self):
pcenter = self.spposinputs.pos
try:
pradius = MathApp.distance(self.posinputs.pos(), self.nposinputs.radius()) * MathApp._scale
except (AttributeError, TypeError):
pradius = self.nposinputs.radius() * MathApp._scale
style = self.stdinputs.style()
fill = self.stdinputs.color()
ymax = pcenter[1]+pradius
ymin = pcenter[1]-pradius
xmax = pcenter[0]+pradius
xmin = pcenter[0]-pradius
try:
if ymin > MathApp.height or ymax < 0 or xmax < 0 or xmin > MathApp.width:
return CircleAsset(pradius, style, fill)
elif pradius > 2*MathApp.width:
# here begins unpleasant hack to overcome crappy circles
poly = self._buildPolygon(pcenter, pradius)
if len(poly):
passet = PolygonAsset(poly, style, fill)
return passet
except AttributeError:
return CircleAsset(pradius, style, fill)
return CircleAsset(pradius, style, fill)
def _buildPolygon(self, pcenter, pradius):
"""
pcenter is in screen relative coordinates.
returns a coordinate list in circle relative coordinates
"""
xcepts = [self._findIntercepts(pcenter, pradius, 0,0,0,MathApp.height),
self._findIntercepts(pcenter, pradius, 0,0,MathApp.width,0),
self._findIntercepts(pcenter, pradius, MathApp.width,0,MathApp.width,MathApp.height),
self._findIntercepts(pcenter, pradius, 0,MathApp.height, MathApp.width, MathApp.height)]
ilist = []
for x in xcepts:
if x and len(x) < 2:
ilist.extend(x)
#ilist is a list of boundary intercepts that are screen-relative
if len(ilist) > 1:
xrange = ilist[-1][0] - ilist[0][0]
yrange = ilist[-1][1] - ilist[0][1]
numpoints = 20
inx = 0
for i in range(numpoints):
icepts = self._findIntercepts(pcenter, pradius,
pcenter[0], pcenter[1],
ilist[0][0] + xrange*(i+1)/(numpoints+1),
ilist[0][1] + yrange*(i+1)/(numpoints+1))
if len(icepts):
ilist.insert(inx+1, icepts[0])
inx = inx + 1
self._addBoundaryVertices(ilist, pcenter, pradius)
ilist.append(ilist[0])
ilist = [(i[0] - pcenter[0], i[1] - pcenter[1]) for i in ilist]
return ilist
def _addBoundaryVertices(self, plist, pcenter, pradius):
"""
Sides 0=top, 1=right, 2=bottom, 3=left
"""
#figure out rotation in point sequence
cw = 0
try:
rtst = plist[0:3]+[plist[0]]
for p in range(3):
cw = cw + (rtst[p+1][0]-rtst[p][0])*(rtst[p+1][1]+rtst[p][1])
except IndexError:
#print(plist)
return
cw = self._sgn(cw)
cw = 1 if cw < 0 else 0
vertices = ((-100,-100),
(MathApp.width+100,-100),
(MathApp.width+100,MathApp.height+100),
(-100,MathApp.height+100))
nextvertex = [(vertices[0],vertices[1]),
(vertices[1],vertices[2]),
(vertices[2],vertices[3]),
(vertices[3],vertices[0])]
nextsides = [(3,1),(0,2),(1,3),(2,0)]
edges = ((None,0),(MathApp.width,None),(None,MathApp.height),(0,None))
endside = startside = None
for side in range(4):
if endside is None and (edges[side][0] == round(plist[-1][0]) or edges[side][1] == round(plist[-1][1])):
endside = side
if startside is None and (edges[side][0] == round(plist[0][0]) or edges[side][1] == round(plist[0][1])):
startside = side
iterations = 0
while startside != endside:
iterations = iterations + 1
if iterations > 20:
break
if endside != None and startside != None: # and endside != startside
plist.append(nextvertex[endside][cw])
endside = nextsides[endside][cw]
def _sgn(self, x):
return 1 if x >= 0 else -1
def _findIntercepts(self, c, r, x1, y1, x2, y2):
"""
c (center) and x and y values are physical, screen relative.
function returns coordinates in screen relative format
"""
x1n = x1 - c[0]
x2n = x2 - c[0]
y1n = y1 - c[1]
y2n = y2 - c[1]
dx = x2n-x1n
dy = y2n-y1n
dr = sqrt(dx*dx + dy*dy)
D = x1n*y2n - x2n*y1n
disc = r*r*dr*dr - D*D
dr2 = dr*dr
if disc <= 0: # less than two solutions
return []
sdisc = sqrt(disc)
x = [(D*dy + self._sgn(dy)*dx*sdisc)/dr2 + c[0], (D*dy - self._sgn(dy)*dx*sdisc)/dr2 + c[0]]
y = [(-D*dx + abs(dy)*sdisc)/dr2 + c[1], (-D*dx - abs(dy)*sdisc)/dr2 + c[1]]
getcoords = lambda x, y, c: [(x,y)] if x>=0 and x<=MathApp.width and y>=0 and y<=MathApp.height else []
res = getcoords(x[0], y[0], c)
res.extend(getcoords(x[1], y[1], c))
return res
@property
def center(self):
return self._center()
@center.setter
def center(self, val):
newval = self.Eval(val)
if newval != self._center:
self._center = newval
self._touchAsset()
@property
def radius(self):
return self._radius()
@radius.setter
def radius(self, val):
newval = self.Eval(val)
if newval != self._radius:
self._radius = newval
self._touchAsset()
def step(self):
self._touchAsset()
def physicalPointTouching(self, ppos):
r = MathApp.distance(self._pcenter, ppos)
inner = self._pradius - self.style.width/2
outer = self._pradius + self.style.width/2
return r <= outer and r >= inner
def translate(self, pdisp):
pass
Ancestors (in MRO)
- Circle
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, *args, **kwargs)
Required Inputs
- pos center of circle
- radius radius of circle (logical) or point on circle
Optional Inputs
- style border line style (thickness, color)
- color fill color
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** center of circle
* **radius** radius of circle (logical) or point on circle
Optional Inputs
* **style** border line style (thickness, color)
* **color** fill color
"""
"""
Radius may be scalar or point
"""
super().__init__(CircleAsset(0, self.defaultstyle, self.defaultcolor), *args, **kwargs)
self._touchAsset()
self.fxcenter = self.fycenter = 0.5
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
r = MathApp.distance(self._pcenter, ppos)
inner = self._pradius - self.style.width/2
outer = self._pradius + self.style.width/2
return r <= outer and r >= inner
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
self.selected = False
Instance variables
var center
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 movable
var position
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.
var radius
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 selectable
var strokable
var visible
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.
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 GlassButton
class GlassButton(InputImageButton):
def __init__(self, callback, *args, **kwargs):
"""
Required Inputs
* **callback** reference of a function to execute, passing this button object
* **pos** position of point
"""
kwargs.setdefault('frame', Frame(0,0,100,100))
kwargs.setdefault('qty', 2)
super().__init__("button-round.png", callback, *args, **kwargs)
self.scale = 0.3
Ancestors (in MRO)
- GlassButton
- InputImageButton
- ImagePoint
- __pdoc_file_module__._Point
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, callback, *args, **kwargs)
Required Inputs
- callback reference of a function to execute, passing this button object
- pos position of point
def __init__(self, callback, *args, **kwargs):
"""
Required Inputs
* **callback** reference of a function to execute, passing this button object
* **pos** position of point
"""
kwargs.setdefault('frame', Frame(0,0,100,100))
kwargs.setdefault('qty', 2)
super().__init__("button-round.png", callback, *args, **kwargs)
self.scale = 0.3
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def distanceTo(
self, otherpoint)
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
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.
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 step(
self)
def step(self):
pass # FIXME
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def unselect(
self)
def unselect(self):
super().unselect()
Instance variables
var center
Inheritance:
ImagePoint
.center
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.
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 movable
var position
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.
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
var strokable
var visible
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.
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 ImageIndicator
class ImageIndicator(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['value']
def __init__(self, url, *args, **kwargs):
"""
Required Inputs
* **url** location of image file consisting of two image sprite sheet
* **pos** position of point
* **value** state of the indicator (True/False or integer)
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
kwargs.setdefault('frame', None)
kwargs.setdefault('qty', 1)
kwargs.setdefault('direction', 'horizontal')
kwargs.setdefault('margin', 0)
super().__init__(
ImageAsset(url,
kwargs['frame'],
kwargs['qty'],
kwargs['direction'],
kwargs['margin']),
*args, **kwargs)
self.center = (0,0)
def _buildAsset(self):
inval = self.nposinputs.value()
if inval == True:
self.setImage(1)
elif inval == False:
self.setImage(0)
else:
self.setImage(inval)
return self.asset
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
def translate(self, pdisp):
pass
Ancestors (in MRO)
- ImageIndicator
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, url, *args, **kwargs)
Required Inputs
- url location of image file consisting of two image sprite sheet
- pos position of point
- value state of the indicator (True/False or integer)
Optional Inputs frame sub-frame location of image within file qty number of sub-frames, when used as sprite sheet direction one of 'horizontal' (default) or 'vertical' margin pixels between sub-frames if sprite sheet
def __init__(self, url, *args, **kwargs):
"""
Required Inputs
* **url** location of image file consisting of two image sprite sheet
* **pos** position of point
* **value** state of the indicator (True/False or integer)
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
kwargs.setdefault('frame', None)
kwargs.setdefault('qty', 1)
kwargs.setdefault('direction', 'horizontal')
kwargs.setdefault('margin', 0)
super().__init__(
ImageAsset(url,
kwargs['frame'],
kwargs['qty'],
kwargs['direction'],
kwargs['margin']),
*args, **kwargs)
self.center = (0,0)
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
self.selected = False
Instance variables
var center
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 movable
var position
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.
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 selectable
var strokable
var visible
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.
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 ImagePoint
class ImagePoint(_Point):
def __init__(self, url, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
frame = kwargs.get('frame', None)
qty = kwargs.get('qty', 1)
direction = kwargs.get('direction', 'horizontal')
margin = kwargs.get('margin', 0)
self._imageasset = ImageAsset(url, frame, qty, direction, margin)
super().__init__(self._imageasset, *args, **kwargs)
def _buildAsset(self):
return self._imageasset
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
Ancestors (in MRO)
- ImagePoint
- __pdoc_file_module__._Point
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, url, *args, **kwargs)
Required Inputs
- url location of image file
- pos position of point
Optional Inputs frame sub-frame location of image within file qty number of sub-frames, when used as sprite sheet direction one of 'horizontal' (default) or 'vertical' margin pixels between sub-frames if sprite sheet
def __init__(self, url, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
frame = kwargs.get('frame', None)
qty = kwargs.get('qty', 1)
direction = kwargs.get('direction', 'horizontal')
margin = kwargs.get('margin', 0)
self._imageasset = ImageAsset(url, frame, qty, direction, margin)
super().__init__(self._imageasset, *args, **kwargs)
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def distanceTo(
self, otherpoint)
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
pass # FIXME
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def unselect(
self)
def unselect(self):
self.selected = False
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 selectable
var strokable
var visible
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.
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 InputButton
class InputButton(Label):
def __init__(self, callback, *args, **kwargs):
"""
Required Inputs
* **pos** position of button
* **text** text of button
* **callback** reference of a function to execute, passing this button object
"""
super().__init__(*args, **kwargs)
self._touchAsset()
self._callback = callback
self.selectable = True
def _buildAsset(self):
return TextAsset(self.nposinputs.text(),
style="bold {0}px Courier".format(self.stdinputs.size()),
width=self.stdinputs.width(),
fill=self.stdinputs.color())
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
def unselect(self):
super().unselect()
Ancestors (in MRO)
- InputButton
- Label
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, callback, *args, **kwargs)
Required Inputs
- pos position of button
- text text of button
- callback reference of a function to execute, passing this button object
def __init__(self, callback, *args, **kwargs):
"""
Required Inputs
* **pos** position of button
* **text** text of button
* **callback** reference of a function to execute, passing this button object
"""
super().__init__(*args, **kwargs)
self._touchAsset()
self._callback = callback
self.selectable = True
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
super().unselect()
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 strokable
var visible
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.
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 InputImageButton
class InputImageButton(ImagePoint):
def __init__(self, url, callback, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **callback** reference of a function to execute, passing this button object
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
super().__init__(url, *args, **kwargs)
self.center = (0,0)
self._callback = callback
self.selectable = True
self.firstImage()
self.mousewasdown = self.mouseisdown
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
def unselect(self):
super().unselect()
def __call__(self):
# code for controlling the button image state only works if the
# button state is being monitored!
if self.mouseisdown != self.mousewasdown:
if self.mouseisdown:
self.nextImage()
else:
self.firstImage()
self.mousewasdown = self.mouseisdown
return self.mouseisdown
Ancestors (in MRO)
- InputImageButton
- ImagePoint
- __pdoc_file_module__._Point
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, url, callback, *args, **kwargs)
Required Inputs
- url location of image file
- callback reference of a function to execute, passing this button object
- pos position of point
Optional Inputs frame sub-frame location of image within file qty number of sub-frames, when used as sprite sheet direction one of 'horizontal' (default) or 'vertical' margin pixels between sub-frames if sprite sheet
def __init__(self, url, callback, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **callback** reference of a function to execute, passing this button object
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **qty** number of sub-frames, when used as sprite sheet
* **direction** one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
"""
super().__init__(url, *args, **kwargs)
self.center = (0,0)
self._callback = callback
self.selectable = True
self.firstImage()
self.mousewasdown = self.mouseisdown
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def distanceTo(
self, otherpoint)
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
if self._callback: self._callback(self)
self.unselect()
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.
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 step(
self)
def step(self):
pass # FIXME
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def unselect(
self)
def unselect(self):
super().unselect()
Instance variables
var center
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 mousewasdown
var movable
var position
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.
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 strokable
var visible
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.
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 InputImageToggle
class InputImageToggle(ImagePoint):
def __init__(self, url, statelist, initindex, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **statelist** list of values to correspond with toggle states
* **initindex** index to initial toggle state
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **direction** for sprite sheet one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
* Note the qty of images is equal to length of the statelist
"""
self.statelist = statelist
kwargs.setdefault('qty', len(statelist))
super().__init__(url, *args, **kwargs)
self.center = (0,0)
self.selectable = True
self.togglestate = initindex
self.setImage(self.togglestate)
def select(self):
super().select()
self.togglestate += 1
if self.togglestate == len(self.statelist):
self.togglestate = 0
self.setImage(self.togglestate)
self.unselect()
def __call__(self):
return self.statelist[self.togglestate]
Ancestors (in MRO)
- InputImageToggle
- ImagePoint
- __pdoc_file_module__._Point
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, url, statelist, initindex, *args, **kwargs)
Required Inputs
- url location of image file
- statelist list of values to correspond with toggle states
- initindex index to initial toggle state
- pos position of point
Optional Inputs frame sub-frame location of image within file direction for sprite sheet one of 'horizontal' (default) or 'vertical' margin pixels between sub-frames if sprite sheet Note the qty of images is equal to length of the statelist
def __init__(self, url, statelist, initindex, *args, **kwargs):
"""
Required Inputs
* **url** location of image file
* **statelist** list of values to correspond with toggle states
* **initindex** index to initial toggle state
* **pos** position of point
Optional Inputs
* **frame** sub-frame location of image within file
* **direction** for sprite sheet one of 'horizontal' (default) or 'vertical'
* **margin** pixels between sub-frames if sprite sheet
* Note the qty of images is equal to length of the statelist
"""
self.statelist = statelist
kwargs.setdefault('qty', len(statelist))
super().__init__(url, *args, **kwargs)
self.center = (0,0)
self.selectable = True
self.togglestate = initindex
self.setImage(self.togglestate)
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def distanceTo(
self, otherpoint)
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
self.togglestate += 1
if self.togglestate == len(self.statelist):
self.togglestate = 0
self.setImage(self.togglestate)
self.unselect()
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.
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 step(
self)
def step(self):
pass # FIXME
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def unselect(
self)
def unselect(self):
self.selected = False
Instance variables
var center
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 movable
var position
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.
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 statelist
var strokable
var togglestate
var visible
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.
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 InputNumeric
class InputNumeric(Label):
def __init__(self, pos, val, **kwargs):
"""
Required Inputs
* **pos** position of button
* **val** initial value of input
Optional Keyword Input
* **fmt** a Python format string (default is {0.2})
"""
self._fmt = kwargs.get('fmt', '{0.2}')
self._val = self.Eval(val)() # initialize to simple numeric
self._savedval = self._val
self._updateText()
super().__init__(pos, self._textValue, **kwargs)
self.selectable = True
def _textValue(self):
return self._text()
def _updateText(self):
self._text = self.Eval(self._fmt.format(self._val))
def processEvent(self, event):
if event.key in "0123456789insertdelete":
key = event.key
if event.key == 'insert':
key = '-'
elif event.key == 'delete':
key = '.'
if self._text() == "0":
self._text = self.Eval("")
self._text = self.Eval(self._text() + key)
self._touchAsset()
elif event.key in ['enter','escape']:
if event.key == 'enter':
try:
self._val = float(self._text())
except ValueError:
self._val = self._savedval
self._savedval = self._val
self.unselect()
def select(self):
super().select()
self._savedval = self._val
self._val = 0
self._updateText()
self._touchAsset()
MathApp.listenKeyEvent("keypress", "*", self.processEvent)
def unselect(self):
super().unselect()
self._val = self._savedval
self._updateText()
self._touchAsset()
try:
MathApp.unlistenKeyEvent("keypress", "*", self.processEvent)
except ValueError:
pass
def __call__(self):
return self._val
Ancestors (in MRO)
- InputNumeric
- Label
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, pos, val, **kwargs)
Required Inputs
- pos position of button
- val initial value of input
Optional Keyword Input * fmt a Python format string (default is {0.2})
def __init__(self, pos, val, **kwargs):
"""
Required Inputs
* **pos** position of button
* **val** initial value of input
Optional Keyword Input
* **fmt** a Python format string (default is {0.2})
"""
self._fmt = kwargs.get('fmt', '{0.2}')
self._val = self.Eval(val)() # initialize to simple numeric
self._savedval = self._val
self._updateText()
super().__init__(pos, self._textValue, **kwargs)
self.selectable = True
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
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.
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 processEvent(
self, event)
def processEvent(self, event):
if event.key in "0123456789insertdelete":
key = event.key
if event.key == 'insert':
key = '-'
elif event.key == 'delete':
key = '.'
if self._text() == "0":
self._text = self.Eval("")
self._text = self.Eval(self._text() + key)
self._touchAsset()
elif event.key in ['enter','escape']:
if event.key == 'enter':
try:
self._val = float(self._text())
except ValueError:
self._val = self._savedval
self._savedval = self._val
self.unselect()
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
self._savedval = self._val
self._val = 0
self._updateText()
self._touchAsset()
MathApp.listenKeyEvent("keypress", "*", self.processEvent)
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
super().unselect()
self._val = self._savedval
self._updateText()
self._touchAsset()
try:
MathApp.unlistenKeyEvent("keypress", "*", self.processEvent)
except ValueError:
pass
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 strokable
var visible
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.
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 LEDIndicator
class LEDIndicator(ImageIndicator):
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of point
* **value** state of the indicator (True/False or integer)
"""
kwargs.setdefault('frame', Frame(0,0,600,600))
kwargs.setdefault('qty', 2)
super().__init__("red-led-off-on.png", *args, **kwargs)
self.scale = 0.05
Ancestors (in MRO)
- LEDIndicator
- ImageIndicator
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, *args, **kwargs)
Required Inputs
- pos position of point
- value state of the indicator (True/False or integer)
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of point
* **value** state of the indicator (True/False or integer)
"""
kwargs.setdefault('frame', Frame(0,0,600,600))
kwargs.setdefault('qty', 2)
super().__init__("red-led-off-on.png", *args, **kwargs)
self.scale = 0.05
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
self.selected = False
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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
var strokable
var visible
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.
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 Label
class Label(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['text']
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of label
* **text** text contents of label
"""
super().__init__(TextAsset(""), *args, **kwargs)
self._touchAsset()
def _buildAsset(self):
return TextAsset(self.nposinputs.text(),
style="{0}px Courier".format(self.stdinputs.size()),
width=self.stdinputs.width(),
fill=self.stdinputs.color())
def __call__(self):
return self.nposinputs.text()
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
def translate(self, pdisp):
pass
Ancestors (in MRO)
- Label
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, *args, **kwargs)
Required Inputs
- pos position of label
- text text contents of label
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of label
* **text** text contents of label
"""
super().__init__(TextAsset(""), *args, **kwargs)
self._touchAsset()
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
self.selected = False
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 selectable
var strokable
var visible
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.
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 LineSegment
class LineSegment(_MathVisual):
posinputsdef = ['pos','end']
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** start position of segment
* **end** end position of segment
Optional Inputs
* **style** line style (thickness, color)
"""
super().__init__(LineAsset(0,0, self.defaultstyle), *args, **kwargs)
self._touchAsset()
def _buildAsset(self):
start = self.pposinputs.pos
end = self.pposinputs.end
self.position = start
return LineAsset(end[0]-start[0],
end[1]-start[1],
self.stdinputs.style())
def physicalPointTouching(self, ppos):
return False
def translate(self, pdisp):
pass
Ancestors (in MRO)
- LineSegment
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, *args, **kwargs)
Required Inputs
- pos start position of segment
- end end position of segment
Optional Inputs
- style line style (thickness, color)
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** start position of segment
* **end** end position of segment
Optional Inputs
* **style** line style (thickness, color)
"""
super().__init__(LineAsset(0,0, self.defaultstyle), *args, **kwargs)
self._touchAsset()
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
return False
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
self.selected = False
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 selectable
var strokable
var visible
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.
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 MathApp
class MathApp(App):
_scale = 200 # pixels per unit
_xcenter = 0 # center of screen in units
_ycenter = 0
_mathVisualList = [] #
_mathDynamicList = []
_mathMovableList = []
_mathSelectableList = []
_mathStrokableList = []
_viewNotificationList = []
time = time()
def __init__(self, scale=_scale):
super().__init__()
MathApp.width = self.width
MathApp.height = self.height
MathApp._scale = scale # pixels per unit
# register event callbacks
self.listenMouseEvent("click", self.handleMouseClick)
self.listenMouseEvent("mousedown", self.handleMouseDown)
self.listenMouseEvent("mouseup", self.handleMouseUp)
self.listenMouseEvent("mousemove", self.handleMouseMove)
self.listenMouseEvent("wheel", self.handleMouseWheel)
self.mouseDown = False
self.mouseCapturedObject = None
self.mouseStrokedObject = None
self.mouseDownObject = None
self.mouseX = self.mouseY = None
self._touchAllVisuals()
self.selectedObj = None
MathApp.time = time()
def step(self):
MathApp.time = time()
for spr in self._mathDynamicList:
spr.step()
def _touchAllVisuals(self):
# touch all visual object assets to use scaling
for obj in self._mathVisualList:
obj._touchAsset(True)
@classmethod
def logicalToPhysical(cls, lp):
xxform = lambda xvalue, xscale, xcenter, physwidth: int((xvalue-xcenter)*xscale + physwidth/2)
yxform = lambda yvalue, yscale, ycenter, physheight: int(physheight/2 - (yvalue-ycenter)*yscale)
try:
return (xxform(lp[0], cls._scale, cls._xcenter, cls._win.width),
yxform(lp[1], cls._scale, cls._ycenter, cls._win.height))
except AttributeError:
return lp
@classmethod
def physicalToLogical(cls, pp):
xxform = lambda xvalue, xscale, xcenter, physwidth: (xvalue - physwidth/2)/xscale + xcenter
yxform = lambda yvalue, yscale, ycenter, physheight: (physheight/2 - yvalue)/yscale + ycenter
try:
return (xxform(pp[0], cls._scale, cls._xcenter, cls._win.width),
yxform(pp[1], cls._scale, cls._ycenter, cls._win.height))
except AttributeError:
return pp
@classmethod
def translatePhysicalToLogical(cls, pp):
xxform = lambda xvalue, xscale: xvalue/xscale
yxform = lambda yvalue, yscale: -yvalue/yscale
try:
return (xxform(pp[0], cls._scale), yxform(pp[1], cls._scale))
except AttributeError:
return pp
@classmethod
def translateLogicalToPhysical(cls, pp):
xxform = lambda xvalue, xscale: xvalue*xscale
yxform = lambda yvalue, yscale: -yvalue*yscale
try:
return (xxform(pp[0], cls._scale), yxform(pp[1], cls._scale))
except AttributeError:
return pp
def handleMouseClick(self, event):
found = False
for obj in self._mathSelectableList:
if obj.physicalPointTouching((event.x, event.y)):
found = True
if not obj.selected:
obj.select()
self.selectedObj = obj
if not found and self.selectedObj:
self.selectedObj.unselect()
self.selectedObj = None
def handleMouseDown(self, event):
self.mouseDown = True
self.mouseCapturedObject = None
self.mouseStrokedObject = None
for obj in self._mathSelectableList:
if obj.physicalPointTouching((event.x, event.y)):
obj.mousedown()
self.mouseDownObject = obj
break
for obj in self._mathMovableList:
if obj.physicalPointTouching((event.x, event.y)) and not (obj.strokable and obj.canstroke((event.x,event.y))):
self.mouseCapturedObject = obj
break
if not self.mouseCapturedObject:
for obj in self._mathStrokableList:
if obj.canstroke((event.x, event.y)):
self.mouseStrokedObject = obj
break
def handleMouseUp(self, event):
if self.mouseDownObject:
self.mouseDownObject.mouseup()
self.mouseDownObject = None
self.mouseDown = False
self.mouseCapturedObject = None
self.mouseStrokedObject = None
def handleMouseMove(self, event):
if not self.mouseX:
self.mouseX = event.x
self.mouseY = event.y
dx = event.x - self.mouseX
dy = event.y - self.mouseY
self.mouseX = event.x
self.mouseY = event.y
if self.mouseDown:
if self.mouseCapturedObject:
self.mouseCapturedObject.translate((dx, dy))
elif self.mouseStrokedObject:
self.mouseStrokedObject.stroke((self.mouseX,self.mouseY), (dx,dy))
else:
lmove = self.translatePhysicalToLogical((dx, dy))
MathApp._xcenter -= lmove[0]
MathApp._ycenter -= lmove[1]
self._touchAllVisuals()
self._viewNotify("translate")
@property
def viewPosition(self):
return (MathApp._xcenter, MathApp._ycenter)
@viewPosition.setter
def viewPosition(self, pos):
MathApp._xcenter, MathApp._ycenter = pos
self._touchAllVisuals()
self._viewNotify("translate")
def handleMouseWheel(self, event):
zoomfactor = event.wheelDelta/100
zoomfactor = 1+zoomfactor if zoomfactor > 0 else 1+zoomfactor
if zoomfactor > 1.2:
zoomfactor = 1.2
elif zoomfactor < 0.8:
zoomfactor = 0.8
MathApp._scale *= zoomfactor
self._touchAllVisuals()
self._viewNotify("zoom")
@classmethod
def addViewNotification(cls, handler):
cls._viewNotificationList.append(handler)
@classmethod
def removeViewNotification(cls, handler):
cls._viewNotificationList.remove(handler)
def _viewNotify(self, viewchange):
for handler in self._viewNotificationList:
handler(viewchange = viewchange, scale = self._scale, center = (self._xcenter, self._ycenter))
@classmethod
def distance(cls, pos1, pos2):
return sqrt((pos2[0]-pos1[0])**2 + (pos2[1]-pos1[1])**2)
@property
def scale(self):
return self._scale
@property
def width(cls):
return App._win.width
@classmethod
def _addVisual(cls, obj):
""" FIX ME """
if isinstance(obj, _MathVisual):
cls._mathVisualList.append(obj)
@classmethod
def _removeVisual(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathVisualList:
cls._mathVisualList.remove(obj)
@classmethod
def _addDynamic(cls, obj):
if isinstance(obj, _MathDynamic) and not obj in cls._mathDynamicList:
cls._mathDynamicList.append(obj)
@classmethod
def _removeDynamic(cls, obj):
if isinstance(obj, _MathDynamic) and obj in cls._mathDynamicList:
cls._mathDynamicList.remove(obj)
@classmethod
def _addMovable(cls, obj):
if isinstance(obj, _MathVisual) and not obj in cls._mathMovableList:
cls._mathMovableList.append(obj)
@classmethod
def _removeMovable(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathMovableList:
cls._mathMovableList.remove(obj)
@classmethod
def _addSelectable(cls, obj):
if isinstance(obj, _MathVisual) and not obj in cls._mathSelectableList:
cls._mathSelectableList.append(obj)
@classmethod
def _removeSelectable(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathSelectableList:
cls._mathSelectableList.remove(obj)
@classmethod
def _addStrokable(cls, obj):
if isinstance(obj, _MathVisual) and not obj in cls._mathStrokableList:
cls._mathStrokableList.append(obj)
@classmethod
def _removeStrokable(cls, obj):
if isinstance(obj, _MathVisual) and obj in cls._mathStrokableList:
cls._mathStrokableList.remove(obj)
@classmethod
def _destroy(cls, *args):
"""
This will clean up any class level storage.
"""
App._destroy(*args) # hit the App class first
MathApp._mathVisualList = []
MathApp._mathDynamicList = []
MathApp._mathMovableList = []
MathApp._mathSelectableList = []
MathApp._mathStrokableList = []
MathApp._viewNotificationList = []
Ancestors (in MRO)
- MathApp
- ggame.App
- builtins.object
Class variables
var spritelist
var time
Static methods
def __init__(
self, scale=200)
def __init__(self, scale=_scale):
super().__init__()
MathApp.width = self.width
MathApp.height = self.height
MathApp._scale = scale # pixels per unit
# register event callbacks
self.listenMouseEvent("click", self.handleMouseClick)
self.listenMouseEvent("mousedown", self.handleMouseDown)
self.listenMouseEvent("mouseup", self.handleMouseUp)
self.listenMouseEvent("mousemove", self.handleMouseMove)
self.listenMouseEvent("wheel", self.handleMouseWheel)
self.mouseDown = False
self.mouseCapturedObject = None
self.mouseStrokedObject = None
self.mouseDownObject = None
self.mouseX = self.mouseY = None
self._touchAllVisuals()
self.selectedObj = None
MathApp.time = time()
def handleMouseClick(
self, event)
def handleMouseClick(self, event):
found = False
for obj in self._mathSelectableList:
if obj.physicalPointTouching((event.x, event.y)):
found = True
if not obj.selected:
obj.select()
self.selectedObj = obj
if not found and self.selectedObj:
self.selectedObj.unselect()
self.selectedObj = None
def handleMouseDown(
self, event)
def handleMouseDown(self, event):
self.mouseDown = True
self.mouseCapturedObject = None
self.mouseStrokedObject = None
for obj in self._mathSelectableList:
if obj.physicalPointTouching((event.x, event.y)):
obj.mousedown()
self.mouseDownObject = obj
break
for obj in self._mathMovableList:
if obj.physicalPointTouching((event.x, event.y)) and not (obj.strokable and obj.canstroke((event.x,event.y))):
self.mouseCapturedObject = obj
break
if not self.mouseCapturedObject:
for obj in self._mathStrokableList:
if obj.canstroke((event.x, event.y)):
self.mouseStrokedObject = obj
break
def handleMouseMove(
self, event)
def handleMouseMove(self, event):
if not self.mouseX:
self.mouseX = event.x
self.mouseY = event.y
dx = event.x - self.mouseX
dy = event.y - self.mouseY
self.mouseX = event.x
self.mouseY = event.y
if self.mouseDown:
if self.mouseCapturedObject:
self.mouseCapturedObject.translate((dx, dy))
elif self.mouseStrokedObject:
self.mouseStrokedObject.stroke((self.mouseX,self.mouseY), (dx,dy))
else:
lmove = self.translatePhysicalToLogical((dx, dy))
MathApp._xcenter -= lmove[0]
MathApp._ycenter -= lmove[1]
self._touchAllVisuals()
self._viewNotify("translate")
def handleMouseUp(
self, event)
def handleMouseUp(self, event):
if self.mouseDownObject:
self.mouseDownObject.mouseup()
self.mouseDownObject = None
self.mouseDown = False
self.mouseCapturedObject = None
self.mouseStrokedObject = None
def handleMouseWheel(
self, event)
def handleMouseWheel(self, event):
zoomfactor = event.wheelDelta/100
zoomfactor = 1+zoomfactor if zoomfactor > 0 else 1+zoomfactor
if zoomfactor > 1.2:
zoomfactor = 1.2
elif zoomfactor < 0.8:
zoomfactor = 0.8
MathApp._scale *= zoomfactor
self._touchAllVisuals()
self._viewNotify("zoom")
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.
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)
def step(self):
MathApp.time = time()
for spr in self._mathDynamicList:
spr.step()
Instance variables
var mouseCapturedObject
var mouseDown
var mouseDownObject
var mouseStrokedObject
var scale
var selectedObj
var viewPosition
var width
Methods
def addViewNotification(
cls, handler)
@classmethod
def addViewNotification(cls, handler):
cls._viewNotificationList.append(handler)
def distance(
cls, pos1, pos2)
@classmethod
def distance(cls, pos1, pos2):
return sqrt((pos2[0]-pos1[0])**2 + (pos2[1]-pos1[1])**2)
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 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.
@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
ggame.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 logicalToPhysical(
cls, lp)
@classmethod
def logicalToPhysical(cls, lp):
xxform = lambda xvalue, xscale, xcenter, physwidth: int((xvalue-xcenter)*xscale + physwidth/2)
yxform = lambda yvalue, yscale, ycenter, physheight: int(physheight/2 - (yvalue-ycenter)*yscale)
try:
return (xxform(lp[0], cls._scale, cls._xcenter, cls._win.width),
yxform(lp[1], cls._scale, cls._ycenter, cls._win.height))
except AttributeError:
return lp
def physicalToLogical(
cls, pp)
@classmethod
def physicalToLogical(cls, pp):
xxform = lambda xvalue, xscale, xcenter, physwidth: (xvalue - physwidth/2)/xscale + xcenter
yxform = lambda yvalue, yscale, ycenter, physheight: (physheight/2 - yvalue)/yscale + ycenter
try:
return (xxform(pp[0], cls._scale, cls._xcenter, cls._win.width),
yxform(pp[1], cls._scale, cls._ycenter, cls._win.height))
except AttributeError:
return pp
def removeViewNotification(
cls, handler)
@classmethod
def removeViewNotification(cls, handler):
cls._viewNotificationList.remove(handler)
def translateLogicalToPhysical(
cls, pp)
@classmethod
def translateLogicalToPhysical(cls, pp):
xxform = lambda xvalue, xscale: xvalue*xscale
yxform = lambda yvalue, yscale: -yvalue*yscale
try:
return (xxform(pp[0], cls._scale), yxform(pp[1], cls._scale))
except AttributeError:
return pp
def translatePhysicalToLogical(
cls, pp)
@classmethod
def translatePhysicalToLogical(cls, pp):
xxform = lambda xvalue, xscale: xvalue/xscale
yxform = lambda yvalue, yscale: -yvalue/yscale
try:
return (xxform(pp[0], cls._scale), yxform(pp[1], cls._scale))
except AttributeError:
return pp
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 MetalToggle
class MetalToggle(InputImageToggle):
def __init__(self, initindex, *args, **kwargs):
"""
Required Inputs
* **initindex** index to initial toggle state
* **pos** position of toggle
"""
kwargs.setdefault('frame', Frame(0,0,110,150))
super().__init__("toggle-up-down.png", [True, False], initindex, *args, **kwargs)
self.scale = 0.4
Ancestors (in MRO)
- MetalToggle
- InputImageToggle
- ImagePoint
- __pdoc_file_module__._Point
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, initindex, *args, **kwargs)
Required Inputs
- initindex index to initial toggle state
- pos position of toggle
def __init__(self, initindex, *args, **kwargs):
"""
Required Inputs
* **initindex** index to initial toggle state
* **pos** position of toggle
"""
kwargs.setdefault('frame', Frame(0,0,110,150))
super().__init__("toggle-up-down.png", [True, False], initindex, *args, **kwargs)
self.scale = 0.4
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def distanceTo(
self, otherpoint)
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
self._setExtents() # ensure xmin, xmax are correct
x, y = ppos
return x >= self.xmin and x < self.xmax and y >= self.ymin and y <= self.ymax
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
self.togglestate += 1
if self.togglestate == len(self.statelist):
self.togglestate = 0
self.setImage(self.togglestate)
self.unselect()
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.
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 step(
self)
def step(self):
pass # FIXME
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def unselect(
self)
def unselect(self):
self.selected = False
Instance variables
var center
Inheritance:
ImagePoint
.center
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.
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 movable
var position
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.
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
var strokable
var visible
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.
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 Point
class Point(_Point):
defaultsize = 5
defaultstyle = LineStyle(0, Color(0, 1))
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of point
"""
super().__init__(CircleAsset(self.defaultsize,
self.defaultstyle, self.defaultcolor), *args, **kwargs)
def _buildAsset(self):
return CircleAsset(self.stdinputs.size(),
self.stdinputs.style(),
self.stdinputs.color())
Ancestors (in MRO)
- Point
- __pdoc_file_module__._Point
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, *args, **kwargs)
Required Inputs
- pos position of point
def __init__(self, *args, **kwargs):
"""
Required Inputs
* **pos** position of point
"""
super().__init__(CircleAsset(self.defaultsize,
self.defaultstyle, self.defaultcolor), *args, **kwargs)
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return False
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
def distanceTo(
self, otherpoint)
def distanceTo(self, otherpoint):
try:
pos = self.posinputs.pos
opos = otherpoint.posinputs.pos
return MathApp.distance(pos, opos())
except AttributeError:
return otherpoint # presumably a scalar - use this distance
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 mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
return MathApp.distance(ppos, self.pposinputs.pos) < self.sstdinputs.size
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
self.selected = True
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.
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 step(
self)
def step(self):
pass # FIXME
self._touchAsset()
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
pass
def translate(
self, pdisp)
def translate(self, pdisp):
ldisp = MathApp.translatePhysicalToLogical(pdisp)
pos = self.posinputs.pos()
self.posinputs = self.posinputs._replace(pos=self.Eval((pos[0] + ldisp[0], pos[1] + ldisp[1])))
self._touchAsset()
def unselect(
self)
def unselect(self):
self.selected = False
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 selectable
var strokable
var visible
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.
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 Slider
class Slider(_MathVisual):
posinputsdef = ['pos']
nonposinputsdef = ['minval','maxval','initial']
def __init__(self, *args, **kwargs):
super().__init__(
RectangleAsset(1, 1), *args, **kwargs)
self._val = self.nposinputs.initial()
self._steps = kwargs.get('steps', 50)
self._step = (self.nposinputs.maxval()-self.nposinputs.minval())/self._steps
self._leftctrl = kwargs.get('leftkey', None)
self._rightctrl = kwargs.get('rightkey', None)
self._centerctrl = kwargs.get('centerkey', None)
self.selectable = True # must be after super init!
self.strokable = True # this enables grabbing/slideing the thumb
self.thumbcaptured = False
self._thumbwidth = max(self.stdinputs.width()/40, 1)
self.thumb = Sprite(RectangleAsset(self._thumbwidth,
self.stdinputs.size()-2, LineStyle(1, self.stdinputs.color()), self.stdinputs.color()),
self.thumbXY())
self._touchAsset()
if self._leftctrl:
MathApp.listenKeyEvent("keydown", self._leftctrl, self.moveLeft)
if self._rightctrl:
MathApp.listenKeyEvent("keydown", self._rightctrl, self.moveRight)
if self._centerctrl:
MathApp.listenKeyEvent("keydown", self._centerctrl, self.moveCenter)
def thumbXY(self):
minval = self.nposinputs.minval()
maxval = self.nposinputs.maxval()
return (self.spposinputs.pos[0]+(self._val-minval)*
(self.sstdinputs.width-self._thumbwidth)/(maxval-minval),
self.spposinputs.pos[1]+1)
def __call__(self):
return self._val
@property
def value(self):
return self._val
@value.setter
def value(self, val):
self._setval(val)
def _buildAsset(self):
self.setThumb()
return RectangleAsset(
self.stdinputs.width(), self.stdinputs.size(),
line=self.stdinputs.style(), fill=Color(0,0))
def setThumb(self):
self.thumb.position = self.thumbXY()
def step(self):
pass
def _setval(self, val):
minval = self.nposinputs.minval()
maxval = self.nposinputs.maxval()
if val <= minval:
self._val = minval
elif val >= maxval:
self._val = maxval
else:
self._val = round((val - minval)*self._steps/(maxval-minval))*self._step + minval
self.setThumb()
def increment(self, step):
self._setval(self._val + step)
def select(self):
super().select()
if not self._leftctrl:
MathApp.listenKeyEvent("keydown", "left arrow", self.moveLeft)
if not self._rightctrl:
MathApp.listenKeyEvent("keydown", "right arrow", self.moveRight)
MathApp.listenMouseEvent("click", self.mouseClick)
def unselect(self):
super().unselect()
try:
if not self._leftctrl:
MathApp.unlistenKeyEvent("keydown", "left arrow", self.moveLeft)
if not self._rightctrl:
MathApp.unlistenKeyEvent("keydown", "right arrow", self.moveRight)
MathApp.unlistenMouseEvent("click", self.mouseClick)
except ValueError:
pass
def mouseClick(self, event):
if self.physicalPointTouching((event.x, event.y)):
if event.x > self.thumb.x + self._thumbwidth:
self.moveRight(event)
elif event.x < self.thumb.x:
self.moveLeft(event)
def moveLeft(self, event):
self.increment(-self._step)
def moveRight(self, event):
self.increment(self._step)
def moveCenter(self, event):
self._val = (self.snposinputs.minval + self.snposinputs.maxval)/2
self.setThumb()
def canstroke(self, ppos):
return self.physicalPointTouchingThumb(ppos)
def stroke(self, ppos, pdisp):
_ppos = self.spposinputs.pos
minval = self.snposinputs.minval
maxval = self.snposinputs.maxval
xpos = ppos[0] + pdisp[0]
self.value = (xpos - _ppos[0])*(maxval-minval)/self.sstdinputs.width + minval
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
def physicalPointTouchingThumb(self, ppos):
thumbpos = self.thumbXY()
return (ppos[0] >= thumbpos[0] and
ppos[0] <= thumbpos[0] + self._thumbwidth + 2 and
ppos[1] >= thumbpos[1] and
ppos[1] <= thumbpos[1] + self.sstdinputs.size - 2)
def translate(self, pdisp):
pass
Ancestors (in MRO)
- Slider
- __pdoc_file_module__._MathVisual
- ggame.Sprite
- __pdoc_file_module__._MathDynamic
- builtins.object
Class variables
var defaultcolor
var defaultsize
var defaultstyle
var defaultwidth
var nonposinputsdef
var posinputsdef
Static methods
def __init__(
self, *args, **kwargs)
def __init__(self, *args, **kwargs):
super().__init__(
RectangleAsset(1, 1), *args, **kwargs)
self._val = self.nposinputs.initial()
self._steps = kwargs.get('steps', 50)
self._step = (self.nposinputs.maxval()-self.nposinputs.minval())/self._steps
self._leftctrl = kwargs.get('leftkey', None)
self._rightctrl = kwargs.get('rightkey', None)
self._centerctrl = kwargs.get('centerkey', None)
self.selectable = True # must be after super init!
self.strokable = True # this enables grabbing/slideing the thumb
self.thumbcaptured = False
self._thumbwidth = max(self.stdinputs.width()/40, 1)
self.thumb = Sprite(RectangleAsset(self._thumbwidth,
self.stdinputs.size()-2, LineStyle(1, self.stdinputs.color()), self.stdinputs.color()),
self.thumbXY())
self._touchAsset()
if self._leftctrl:
MathApp.listenKeyEvent("keydown", self._leftctrl, self.moveLeft)
if self._rightctrl:
MathApp.listenKeyEvent("keydown", self._rightctrl, self.moveRight)
if self._centerctrl:
MathApp.listenKeyEvent("keydown", self._centerctrl, self.moveCenter)
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def canstroke(
self, ppos)
def canstroke(self, ppos):
return self.physicalPointTouchingThumb(ppos)
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 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.
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)
def destroy(self):
MathApp._removeVisual(self)
MathApp._removeMovable(self)
MathApp._removeStrokable(self)
_MathDynamic.destroy(self)
Sprite.destroy(self)
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 increment(
self, step)
def increment(self, step):
self._setval(self._val + step)
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 mouseClick(
self, event)
def mouseClick(self, event):
if self.physicalPointTouching((event.x, event.y)):
if event.x > self.thumb.x + self._thumbwidth:
self.moveRight(event)
elif event.x < self.thumb.x:
self.moveLeft(event)
def mousedown(
self)
def mousedown(self):
self.mouseisdown = True
def mouseup(
self)
def mouseup(self):
self.mouseisdown = False
def moveCenter(
self, event)
def moveCenter(self, event):
self._val = (self.snposinputs.minval + self.snposinputs.maxval)/2
self.setThumb()
def moveLeft(
self, event)
def moveLeft(self, event):
self.increment(-self._step)
def moveRight(
self, event)
def moveRight(self, event):
self.increment(self._step)
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.
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 physicalPointTouching(
self, ppos)
def physicalPointTouching(self, ppos):
_ppos = self.spposinputs.pos
return (ppos[0] >= _ppos[0] and
ppos[0] <= _ppos[0] + self.sstdinputs.width and
ppos[1] >= _ppos[1] and
ppos[1] <= _ppos[1] + self.sstdinputs.size)
def physicalPointTouchingThumb(
self, ppos)
def physicalPointTouchingThumb(self, ppos):
thumbpos = self.thumbXY()
return (ppos[0] >= thumbpos[0] and
ppos[0] <= thumbpos[0] + self._thumbwidth + 2 and
ppos[1] >= thumbpos[1] and
ppos[1] <= thumbpos[1] + self.sstdinputs.size - 2)
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.
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 processEvent(
self, event)
def processEvent(self, event):
pass
def rectangularCollisionModel(
self)
Obsolete. No op.
def rectangularCollisionModel(self):
"""
Obsolete. No op.
"""
pass
def select(
self)
def select(self):
super().select()
if not self._leftctrl:
MathApp.listenKeyEvent("keydown", "left arrow", self.moveLeft)
if not self._rightctrl:
MathApp.listenKeyEvent("keydown", "right arrow", self.moveRight)
MathApp.listenMouseEvent("click", self.mouseClick)
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.
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 setThumb(
self)
def setThumb(self):
self.thumb.position = self.thumbXY()
def step(
self)
def step(self):
pass
def stroke(
self, ppos, pdisp)
def stroke(self, ppos, pdisp):
_ppos = self.spposinputs.pos
minval = self.snposinputs.minval
maxval = self.snposinputs.maxval
xpos = ppos[0] + pdisp[0]
self.value = (xpos - _ppos[0])*(maxval-minval)/self.sstdinputs.width + minval
def thumbXY(
self)
def thumbXY(self):
minval = self.nposinputs.minval()
maxval = self.nposinputs.maxval()
return (self.spposinputs.pos[0]+(self._val-minval)*
(self.sstdinputs.width-self._thumbwidth)/(maxval-minval),
self.spposinputs.pos[1]+1)
def translate(
self, pdisp)
def translate(self, pdisp):
pass
def unselect(
self)
def unselect(self):
super().unselect()
try:
if not self._leftctrl:
MathApp.unlistenKeyEvent("keydown", "left arrow", self.moveLeft)
if not self._rightctrl:
MathApp.unlistenKeyEvent("keydown", "right arrow", self.moveRight)
MathApp.unlistenMouseEvent("click", self.mouseClick)
except ValueError:
pass
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 ggame.Sprite.fxcenter
and ggame.Sprite.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 movable
var position
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.
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 selectable
var strokable
var thumb
var thumbcaptured
var value
var visible
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.
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 Timer
class Timer(_MathDynamic):
def __init__(self):
super().__init__()
self.once = []
self.callbacks = {}
self.reset()
self.step()
self._start = self._reset #first time
self.next = None
MathApp._addDynamic(self) # always dynamically defined
def reset(self):
self._reset = MathApp.time
def step(self):
nexttimers = []
calllist = []
self.time = MathApp.time - self._reset
while self.once and self.once[0][0] <= MathApp.time:
tickinfo = self.once.pop(0)
if tickinfo[1]: # periodic?
nexttimers.append((tickinfo[1], self.callbacks[tickinfo][0])) # delay, callback
calllist.append(self.callbacks[tickinfo].pop(0)) # remove callback and queue it
if not self.callbacks[tickinfo]: # if the callback list is empty
del self.callbacks[tickinfo] # remove the dictionary entry altogether
for tickadd in nexttimers:
self.callAfter(tickadd[0], tickadd[1], True) # keep it going
for call in calllist:
call(self)
def callAfter(self, delay, callback, periodic=False):
key = (MathApp.time + delay, delay if periodic else 0)
self.once.append(key)
callbacklist = self.callbacks.get(key, [])
callbacklist.append(callback)
self.callbacks[key] = callbacklist
self.once.sort()
def callAt(self, time, callback):
self.callAfter(time-self.time, callback)
def callEvery(self, period, callback):
self.callAfter(period, callback, True)
def __call__(self):
return self.time
Ancestors (in MRO)
- Timer
- __pdoc_file_module__._MathDynamic
- builtins.object
Static methods
def __init__(
self)
def __init__(self):
super().__init__()
self.once = []
self.callbacks = {}
self.reset()
self.step()
self._start = self._reset #first time
self.next = None
MathApp._addDynamic(self) # always dynamically defined
def Eval(
self, val)
def Eval(self, val):
if callable(val):
self._setDynamic() # dynamically defined .. must step
return val
else:
return lambda : val
def callAfter(
self, delay, callback, periodic=False)
def callAfter(self, delay, callback, periodic=False):
key = (MathApp.time + delay, delay if periodic else 0)
self.once.append(key)
callbacklist = self.callbacks.get(key, [])
callbacklist.append(callback)
self.callbacks[key] = callbacklist
self.once.sort()
def callAt(
self, time, callback)
def callAt(self, time, callback):
self.callAfter(time-self.time, callback)
def callEvery(
self, period, callback)
def callEvery(self, period, callback):
self.callAfter(period, callback, True)
def destroy(
self)
def destroy(self):
MathApp._removeDynamic(self)
def reset(
self)
def reset(self):
self._reset = MathApp.time
def step(
self)
def step(self):
nexttimers = []
calllist = []
self.time = MathApp.time - self._reset
while self.once and self.once[0][0] <= MathApp.time:
tickinfo = self.once.pop(0)
if tickinfo[1]: # periodic?
nexttimers.append((tickinfo[1], self.callbacks[tickinfo][0])) # delay, callback
calllist.append(self.callbacks[tickinfo].pop(0)) # remove callback and queue it
if not self.callbacks[tickinfo]: # if the callback list is empty
del self.callbacks[tickinfo] # remove the dictionary entry altogether
for tickadd in nexttimers:
self.callAfter(tickadd[0], tickadd[1], True) # keep it going
for call in calllist:
call(self)
Instance variables
var callbacks
var next
var once