Source code for ggame.asset

"""
ggame assets and related objects (:class:`Color` and :class:`LineStyle`) are
classes that encapsulate and represent displayable images. A single asset
may be used in multiple sprites. Animated assets may be created from any
image that includes multiple images within it (i.e. a sprite sheet).
"""

from ggame.sysdeps import (
    GFX_Rectangle,
    GFX_Texture,
    GFX_Graphics,
    GFX_Texture_fromImage,
    GFX_Text,
)


[docs] class Frame(object): # pylint: disable=useless-object-inheritance """ Frame is a utility class for expressing the idea of a rectangular region. Initializing parameters describe the position of the upper-left corner of the frame, and the frame's width and height. The units are *typically* in pixels, though a frame can be generic. :param int x: X-coordinate of frame upper-left corner :param int y: Y-coordinate of frame upper-left corner :param int w: Width of the frame :param int h: Height of the frame """ def __init__(self, x, y, w, h): self.gfx = GFX_Rectangle(x, y, w, h) """ `_gfx` is a reference to the underlying object provided by the system. """ self.x = x self.y = y self.w = w self.h = h @property def x(self): """ X-coordinate of the upper left hand corner of this frame. """ return self.gfx.x @x.setter def x(self, value): self.gfx.x = value @property def y(self): """ Y-coordinate of the upper left hand corner of this frame. """ return self.gfx.y @y.setter def y(self, value): self.gfx.y = value @property def w(self): """ Width of the frame. """ return self.gfx.width @w.setter def w(self, value): self.gfx.width = value @property def h(self): """ Height of the frame. """ return self.gfx.height @h.setter def h(self, value): self.gfx.height = value @property def center(self): """ The `center` property computes a coordinate pair (tuple) for the center of the frame. The `center` property, when set, redefines the `x` and `y` properties of the frame in order to make the center agree with the coordinates (tuple) assigned to it. """ return (self.x + self.w // 2, self.y + self.h // 2) @center.setter def center(self, value): c = self.center self.x += value[0] - c[0] self.y += value[1] - c[1]
class _Asset(object): # pylint: disable=useless-object-inheritance """ Base class for all game asset objects. The `ggame.Asset` class is set up to understand the concept of multiple instances of an asset. This is currently only used for image-based assets. """ def __init__(self): self.gfxlist = [None] """ A list of the underlying system objects used to represent this asset. """ @property def gfx(self): """ `gfx` property represents the underlying system object used to represent this asset. If this asset is composed of multiple assets, then the **first** asset is referenced by `gfx`. """ return self.gfxlist[0] @gfx.setter def gfx(self, value): self.gfxlist[0] = value def __len__(self): return len(self.gfxlist) def __getitem__(self, key): return self.gfxlist[key] def __setitem__(self, key, value): self.gfxlist[key] = value def __iter__(self): class Iter: """ Iterator for accessing discrete images within an asset. """ def __init__(self, image): self.obj = image self.n = len(image.gfxlist) self.i = 0 def __iter__(self): return self def __next__(self): if self.i == self.n: raise StopIteration self.i += 1 return self.obj.gfxlist[self.i] return Iter(self) def destroy(self): """ Destroy or deallocate any underlying graphics resources used by the asset. Call this method on any asset that is no longer being used. """ if hasattr(self, "gfx"): try: for gfx in self.gfxlist: try: gfx.destroy(True) except BaseException: pass except BaseException: pass
[docs] class ImageAsset(_Asset): """ The ImageAsset class connects ggame to a specific image **file**. :param str url: All ImageAsset instances must specify a file name or url where a jpg or png image is located. :param Frame frame: If the desired sprite image exists in only a smaller sub-section of the original image, then specify an area `within` the image using `frame` parameter, which must be a valid :class:`Frame` instance. :param int qty=0: If the image file actually is a *collection* of images, such as a so-called *sprite sheet*, then the ImageAsset class supports defining a list of images, provided they exist in the original image as a **row** of evenly spaced images or a **column** of images. To specify this, provide the `qty` (quantity) of images in the row or column. :param str direction='horizontal': For an image *sprite sheet*, specify whether the images are oriented in a `'vertical'` or `'horizontal'` arrangement. :param int margin=0: If there is a gap between successive images in an image *sprite sheet*, then specify the size of the gap (in pixels). When used in this way, the `frame` parameter must define the area of only the **first** image in the collection; all subsequent images in the list are assumed to be the same size, but separated by the `margin` value. Example: .. literalinclude:: ../examples/assetimage.py """ def __init__(self, url, frame=None, qty=1, direction="horizontal", margin=0): super().__init__() self.url = url """ A string that represents the path or url of the original file. """ del self.gfxlist[0] self.width = self.height = 0 self.append(url, frame, qty, direction, margin)
[docs] def append(self, url, frame=None, qty=1, direction="horizontal", margin=0): """ Append a texture asset from a new image file (or url). This method allows you to build a collection of images into an asset (such as you might need for an animated sprite), but without using a single sprite sheet image. The parameters for the `append` method are identical to those supplied to the :class:`ImageAsset` initialization method. This method allows you to build up an asset that consists of multiple rows or columns of images in a sprite sheet or sheets. """ gfx = GFX_Texture_fromImage(url, False) dx = 0 dy = 0 for i in range(qty): if frame is not None: self.width = frame.w self.height = frame.h if direction == "horizontal": dx = frame.w + margin elif direction == "vertical": dy = frame.h + margin f = Frame(frame.x + dx * i, frame.y + dy * i, frame.w, frame.h) gfx = GFX_Texture(gfx, f.gfx) else: self.width = gfx.width self.height = gfx.height self.gfxlist.append(gfx)
[docs] class Color: """ The Color class is used to represent colors and/or colors with transparency. :param int color: an integer in the conventional format (usually as a hexadecimal literal, e.g. 0xffbb33 that represents the three color components, red, green and blue) :param float alpha: a transparency value, or `alpha` as a floating-point number in the range of 0.0 to 1.0 where 0.0 represents completely transparent and 1.0 represents completely opaque. Example: .. literalinclude:: ../examples/assetcolor.py """ _colornames = {0xFFFFFF: "WHITE", 0x000000: "BLACK"} def __init__(self, color, alpha): self.color = color self.alpha = alpha self.name = f"Color(0x{int(self.color):06X}, {self.alpha})" if alpha == 1.0: self.name = self._colornames.get(self.color, self.name) def __eq__(self, other): return ( isinstance(self, type(other)) and self.color == other.color and self.alpha == other.alpha ) def __repr__(self): return self.name
BLACK = Color(0x000000, 1.0) """ Default black color """ WHITE = Color(0xFFFFFF, 1.0) """ Default white color """
[docs] class LineStyle: """ The LineStyle class is used to represent line style when drawing geometrical objects such as rectangles, ellipses, etc. :param int width: the `width` of the line in pixels :param Color color: the `color` as a valid :class:`Color` instance. Example: .. literalinclude:: ../examples/assetlinestyle.py This defines a 3-pixel wide green line. """ def __init__(self, width, color): """ """ self.width = width self.color = color def __eq__(self, other): return ( isinstance(self, type(other)) and self.width == other.width and self.color == other.color ) def __repr__(self): return f"LineStyle({self.width}, {self.color})"
BLACKLINE = LineStyle(1, BLACK) """ Default thin black line """ WHITELINE = LineStyle(1, WHITE) """ Default thin white line """ class _GraphicsAsset(_Asset): def __init__(self): super().__init__() GFX_Graphics.clear() class _CurveAsset(_GraphicsAsset): def __init__(self, line): super().__init__() GFX_Graphics.lineStyle(line.width, line.color.color, line.color.alpha) class _ShapeAsset(_CurveAsset): def __init__(self, line, fill): super().__init__(line) GFX_Graphics.beginFill(fill.color, fill.alpha)
[docs] class RectangleAsset(_ShapeAsset): """ The RectangleAsset is a "virtual" asset that is created on the fly without requiring creation of an image file. :param int width: Rectangle width, in pixels :param int height: Rectangle height, in pixels :param LineStyle line=BLACKLINE: The color and width of the rectangle border :param Color fill=BLACK: The color of the rectangle body """ def __init__(self, width, height, line=BLACKLINE, fill=BLACK): super().__init__(line, fill) self.width = width self.height = height self.gfx = GFX_Graphics.drawRect(0, 0, self.width, self.height).clone() """The `gfx` property represents the underlying system object.""" self.gfx.visible = False
[docs] class CircleAsset(_ShapeAsset): """ The `ggame.CircleAsset` is a "virtual" asset that is created on the fly without requiring creation of an image file. :param int radius: Circle radius, in pixels :param LineStyle line=BLACKLINE: The color and width of the circle border :param Color fill=BLACK: The color of the circle body """ def __init__(self, radius, line=BLACKLINE, fill=BLACK): super().__init__(line, fill) self.radius = radius self.gfx = GFX_Graphics.drawCircle(0, 0, self.radius).clone() """The `gfx` property represents the underlying system object.""" self.gfx.visible = False
[docs] class EllipseAsset(_ShapeAsset): """ The `ggame.EllipseAsset` is a "virtual" asset that is created on the fly without requiring creation of an image file. :param int halfw: Ellipse semi-axis dimension in the horizontal direction (half the width of the ellipse), in pixels :param int halfh: Ellipse semi-axis dimension in the vertical direction (half the height of the ellipse), in pixels :param LineStyle line=BLACKLINE: The color and width of the ellipse border :param Color fill=BLACK: The color of the ellipse body """ def __init__(self, halfw, halfh, line=BLACKLINE, fill=BLACK): super().__init__(line, fill) self.halfw = halfw self.halfh = halfh self.gfx = GFX_Graphics.drawEllipse(0, 0, self.halfw, self.halfh).clone() """The `gfx` property represents the underlying system object.""" self.gfx.visible = False
[docs] class PolygonAsset(_ShapeAsset): """ The PolygonAsset is a "virtual" asset that is created on the fly without requiring creation of an image file. Note: you should not specificy absolute screen coordinates for this asset, since you will use the :class:`Sprite` position to locate your polygon on the screen. :param list path: A list of pixel-coordinate tuples. These coordinates should not be in absolute screen coordinates, but should be relative to the desired 'center' of the resulting :class:`Sprite`. The final coordinate pair in the list must be the same as the first. :param LineStyle line=BLACKLINE: The color and width of the ellipse border :param Color fill=BLACK: The color of the ellipse body Example: .. literalinclude:: ../examples/assetpolygon.py """ def __init__(self, path, line=BLACKLINE, fill=BLACK): super().__init__(line, fill) self.path = path[:] jpath = [] # close the path if necessary if self.path[0] != self.path[-1]: self.path.append(self.path[0]) for point in self.path: jpath.extend(point) self.gfx = GFX_Graphics.drawPolygon(jpath).clone() """The `gfx` property represents the underlying system object.""" self.gfx.visible = False
[docs] class LineAsset(_CurveAsset): """ The LineAsset is a "virtual" asset that is created on the fly without requiring creation of an image file. A LineAsset instance represents a single line segment. Note: you should not specificy absolute screen coordinates for this asset, since you will use the :class:`Sprite` position to locate your line on the screen. The line segment will begin at pixel coordinates (0,0), and will end at the (x,y) coordinates given below. As the LineAsset does not cover a region, only a :class:`LineStyle` argument must be supplied (`line`) to specify the color. :param int x: x-coordinate of the line endpoint, in pixel units :param int y: y-coordinate of the line endpoint, in pixel units :param LineStyle line=BLACKLINE: The color and width of the ellipse border """ def __init__(self, x, y, line=BLACKLINE): super().__init__(line) self.delta_x = x """ This attribute represents the `x` parameter supplied during instantiation. """ self.delta_y = y """ This attribute represents the `y` parameter supplied during instantiation. """ GFX_Graphics.moveTo(0, 0) self.gfx = GFX_Graphics.lineTo(self.delta_x, self.delta_y).clone() """The `gfx` property represents the underlying system object.""" self.gfx.visible = False
[docs] class TextAsset(_GraphicsAsset): """ The TextAsset is a "virtual" asset that is created on the fly without requiring creation of an image file. A TextAsset instance represents a block of text, together with its styling (font, color, etc.). :param str text: The text that should be displayed :param \\**kwargs: Optional formatting and style attributes (below) :param str style='20px Arial': Text style, size and typeface. Example:: 'italic 20pt Helvetica' :keyword int width=100: Width of the text block on screen, in pixels. :param Color fill=BLACK: :class:`Color` instance to specify color and transparency of the text. :param str align='left': Alignment style of the block. One of 'left', 'center', or 'right'. Full example: .. literalinclude:: ../examples/assettext.py """ def __init__(self, text, **kwargs): """ """ super().__init__() self.text = text self.style = kwargs.get("style", "20px Arial") width = kwargs.get("width", 100) self.fill = kwargs.get("fill", Color(0, 1)) self.align = kwargs.get("align", "left") self.gfx = GFX_Text( self.text, { "font": self.style, "fill": self.fill.color, "align": self.align, "wordWrap": True, "wordWrapWidth": width, }, ) self.gfx.alpha = self.fill.alpha self.gfx.visible = False
[docs] def clone(self): """ Create a duplicate asset with the current style settings. :returns: A text asset that is identical to the original, but with current styles. :rtype: TextAsset """ return type(self)( self.text, style=self.style, width=self.width, fill=self.fill, align=self.align, )
@property def width(self): """ Width of the rendered text asset in pixels """ return self.gfx.width @property def height(self): """ Height of the rendered text asset in pixels """ return self.gfx.height