xnano.art
xnano.art
¶
xnano.art
Pixel art written as text, and pixel worlds: art that holds other art, seen through a camera, with solid ground to collide against.
Classes:
Functions:
-
draw–Build pixel art from text, a picture, bytes or nothing (does not draw).
Camera
¶
Which part of a world is on screen.
By default the camera stays put. follow an art to keep it in
the middle, or set x and y yourself. Either way the camera stays inside the world,
and a world smaller than the screen is centered.
Attributes:
-
x–The world column at the left edge of the screen, when nothing is followed.
-
y–The world row at the top edge of the screen, when nothing is followed.
-
target(Art | None) –The art the camera follows, or
None.
Examples:
import xnano
world = xnano.draw(None, width=100, height=60, background='black')
hero = world.add(xnano.draw(['H', 'H'], {'H': 'red'}), x=50, y=30)
world.camera.follow(hero)
assert world.camera.target is hero
Create a camera. Every art has one as art.camera.
Methods:
-
follow–Keep an art in the middle of the screen, or pass
Noneto stop following.
Source code in xnano/art.py
Art
¶
Art(rgba: bytes | bytearray | None, width: int, height: int, *, background: ColorValue | None = None, symbol: str | None = None, effects: Sequence[RenderableEffectSpecification] = ())
Pixel art, and a world that holds other art.
Make one with draw. A pixel is half a cell tall, so art that is 8 pixels
tall takes 4 rows of a canvas. Write it with canvas.write(art), or print it on its
own with render.
An art can hold other art: add puts a child at a position in the
world, and the world is drawn through its camera. Change any
attribute of an art or of a child and the canvas draws it again on the next frame; nothing
else is needed, and a world that stands still costs nothing. Positions and sizes of art are
in pixels and may be fractional; a child is drawn at its rounded position. A child's
x and y place it inside its parent in pixels, while placement.x and
placement.y place the whole art on the canvas in cells: art.up() moves one pixel,
half a cell, and placement.up() moves one cell.
Attributes:
-
width(int) –The width in pixels.
-
height(int) –The height in pixels (two pixel rows make one cell row).
-
x(float) –The pixel column of the anchor inside the parent art.
-
y(float) –The pixel row of the anchor inside the parent art.
-
layer(int) –Children with a higher layer are drawn over lower ones.
-
is_visible(bool) –Whether the art is drawn.
-
anchor(Anchor) –The
(x, y)pixel inside the art that sits at(x, y). -
background(Color | None) –The color behind the art and its children, or
Nonefor none. -
solid_map(bytes | bytearray | None) –Which pixels of the art's world cannot be walked on, or
None. -
camera–What part of the world is on screen.
-
symbol(str | None) –The name the art is registered under in
symbols, orNone.
Examples:
import xnano
world = xnano.draw(None, width=40, height=20, background='black')
hero = world.add(xnano.draw(['HH', 'HH'], {'H': 'red'}), x=10, y=10, anchor=(1, 1))
hero.move(2, 0)
assert hero.x == 12
with xnano.new(width=20, height=5) as canvas:
canvas.write(world, width='100%', height='100%')
canvas.step()
Create art from pixels. Use draw instead of calling this.
Parameters:
-
rgba(bytes | bytearray | None) –width * height * 4bytes of red, green, blue and alpha, orNonefor a world with no pixels of its own. -
width(int) –The width in pixels.
-
height(int) –The height in pixels.
-
background(ColorValue | None, default:None) –The color behind the art.
-
symbol(str | None, default:None) –The name to register the art under.
-
effects(Sequence[RenderableEffectSpecification], default:()) –Effects to start on the placement when the art is written.
Methods:
-
add–Put another art in this one, at a position in pixels.
-
replace–Swap the pixels for others, keeping the position, layer and parent.
-
remove–Take the art out of the art that holds it. Removing a loose art does nothing.
-
move–Move the art by a number of pixels, sliding along solid ground instead of stopping.
-
up–Move up by
countpixels, sliding along solid ground, and say how far it got. -
down–Move down by
countpixels, sliding along solid ground, and say how far it got. -
left–Move left by
countpixels, sliding along solid ground, and say how far it got. -
right–Move right by
countpixels, sliding along solid ground, and say how far it got. -
is_solid–Whether a pixel of this art's world cannot be walked on.
-
world_for_cell–The world pixel under a cell of the screen, such as the one the pointer is over.
-
render–Draw the art to a string, without a canvas.
-
__xnano_render__–Return the cells that show the art, as large as the area it is written in.
Source code in xnano/art.py
background
property
writable
¶
background: Color | None
The color behind the art and its children, or None for none.
solid_map
property
writable
¶
add
¶
add(art: Art, /, *, x: float = 0, y: float = 0, layer: int = 0, anchor: Anchor = (0, 0), is_solid: bool = False) -> Art
Put another art in this one, at a position in pixels.
Parameters:
-
art(Art) –The art to add. It may be added to one art only.
-
x(float, default:0) –The pixel column of the child's anchor inside this art.
-
y(float, default:0) –The pixel row of the child's anchor inside this art.
-
layer(int, default:0) –Children with a higher layer are drawn over lower ones; children on the same layer are drawn in the order they were added.
-
anchor(Anchor, default:(0, 0)) –The
(x, y)pixel of the child that sits at(x, y). -
is_solid(bool, default:False) –Whether the child's opaque pixels block the movement of other children.
Returns:
-
Art–The child, to move, change or remove.
Raises:
-
ValueError–The art already belongs to an art, or is this art or one that holds it.
Examples:
import xnano
world = xnano.draw(None, width=8, height=8)
hero = world.add(xnano.draw(['R', 'R'], {'R': 'red'}), x=3, y=2, anchor=(0, 1))
assert (hero.x, hero.y) == (3, 2)
Source code in xnano/art.py
replace
¶
replace(source: str | Sequence[str] | Image | TerminalImage | bytes | bytearray | None, palette: Mapping[str, ColorValue] | str | None = None, *, width: int | None = None, height: int | None = None) -> None
Swap the pixels for others, keeping the position, layer and parent.
The solid ground is kept when the new pixels have the same size and cleared when the size changes.
This is how a walk cycle or a zoom is made: draw every frame once, and replace the
pixels of the art that is on screen. The sources are the ones
draw takes, except a symbol name.
Parameters:
-
source(str | Sequence[str] | Image | TerminalImage | bytes | bytearray | None) –Text rows, an image, RGBA bytes or
None. -
palette(Mapping[str, ColorValue] | str | None, default:None) –What each character of text rows means.
-
width(int | None, default:None) –The width in pixels of RGBA bytes or of a blank world.
-
height(int | None, default:None) –The height in pixels.
Examples:
import xnano
frame_one = ['AB']
hero = xnano.draw(frame_one, {'A': 'red', 'B': 'blue'})
hero.replace(['BA'], {'A': 'red', 'B': 'blue'})
assert hero.width == 2
Source code in xnano/art.py
remove
¶
Take the art out of the art that holds it. Removing a loose art does nothing.
Source code in xnano/art.py
move
¶
Move the art by a number of pixels, sliding along solid ground instead of stopping.
The two axes are tried one after the other, a pixel at a time, so walking diagonally
into a wall keeps moving along it and a thin wall cannot be stepped over. The anchor
pixel is what collides. An art without a parent art, or whose parent has no solid
ground, moves freely. Positive x moves right and positive y moves down.
Pixels are half a cell: art.move(y=-1) moves one pixel up, where
placement.move(y=-1) moves the whole art one cell up.
Parameters:
-
x(float, default:0) –How far to move along
x, in pixels. -
y(float, default:0) –How far to move along
y, in pixels.
Returns:
Examples:
import xnano
world = xnano.draw(None, width=8, height=8)
solid = bytearray(64)
for row in range(8):
solid[row * 8 + 5] = 1
world.solid_map = solid
hero = world.add(xnano.draw(['R'], {'R': 'red'}), x=4, y=2)
assert hero.move(2, 1) == (0.0, 1.0)
assert (hero.x, hero.y) == (4, 3)
Source code in xnano/art.py
up
¶
Move up by count pixels, sliding along solid ground, and say how far it got.
Unlike Placement.up, which returns the placement
so calls chain, this returns the distance moved, so a game can tell when the art was
blocked.
Parameters:
-
count(float, default:1) –How many pixels to move; pixels are half a cell.
Returns:
-
float–The distance moved in pixels,
0.0when blocked.
Source code in xnano/art.py
down
¶
Move down by count pixels, sliding along solid ground, and say how far it got.
Unlike Placement.down, which returns the placement
so calls chain, this returns the distance moved, so a game can tell when the art was
blocked.
Parameters:
-
count(float, default:1) –How many pixels to move; pixels are half a cell.
Returns:
-
float–The distance moved in pixels,
0.0when blocked.
Source code in xnano/art.py
left
¶
Move left by count pixels, sliding along solid ground, and say how far it got.
Unlike Placement.left, which returns the placement
so calls chain, this returns the distance moved, so a game can tell when the art was
blocked.
Parameters:
-
count(float, default:1) –How many pixels to move; pixels are half a cell.
Returns:
-
float–The distance moved in pixels,
0.0when blocked.
Source code in xnano/art.py
right
¶
Move right by count pixels, sliding along solid ground, and say how far it got.
Unlike Placement.right, which returns the placement
so calls chain, this returns the distance moved, so a game can tell when the art was
blocked.
Parameters:
-
count(float, default:1) –How many pixels to move; pixels are half a cell.
Returns:
-
float–The distance moved in pixels,
0.0when blocked.
Source code in xnano/art.py
is_solid
¶
Whether a pixel of this art's world cannot be walked on.
Everything outside the world is solid. Inside it, a pixel is solid where
solid_map holds a non-zero byte, or where an opaque pixel
of a child added with is_solid=True is.
Parameters:
Examples:
import xnano
world = xnano.draw(None, width=4, height=4)
assert world.is_solid(-1, 0)
assert not world.is_solid(2, 2)
Source code in xnano/art.py
world_for_cell
¶
The world pixel under a cell of the screen, such as the one the pointer is over.
The cell must be one of the cells the art was last drawn in; a cell is two pixels tall, and the pixel returned is the lower one.
Parameters:
-
x(int) –The cell's column in the placement of the art.
-
y(int) –The cell's row in the placement of the art.
Examples:
import xnano
world = xnano.draw(None, width=40, height=40)
world.camera.x, world.camera.y = 16, 16
with xnano.new(width=8, height=4) as canvas:
canvas.write(world, width='100%', height='100%')
canvas.step()
assert world.world_for_cell(0, 0) == (16, 17)
Source code in xnano/art.py
render
¶
render(*, width: int | None = None, height: int | None = None, format: Literal['text', 'ansi'] = 'text') -> str
Draw the art to a string, without a canvas.
Parameters:
-
width(int | None, default:None) –The width in cells. The art's own width by default.
-
height(int | None, default:None) –The height in cells. The art's own height in cells by default.
-
format(Literal['text', 'ansi'], default:'text') –'text'for the characters only,'ansi'with colors.
Examples:
Source code in xnano/art.py
__xnano_render__
¶
Return the cells that show the art, as large as the area it is written in.
Source code in xnano/art.py
draw
¶
draw(source: str | Sequence[str] | Image | TerminalImage | bytes | bytearray | None = None, palette: Mapping[str, ColorValue] | str | None = None, *, width: int | None = None, height: int | None = None, background: ColorValue | None = None, symbol: str | None = None, effects: Sequence[RenderableEffectSpecification] = ()) -> Art
Build pixel art from text, a picture, bytes or nothing (does not draw).
This is how pixel-art sprites are written in code, one character per pixel. Nothing is
drawn: the art is a value that you write into a canvas. Text rows (a multi-line string, which
may be indented, or a list of rows) are painted with a palette that says what each
character means; any character the palette does not name, such as '.', is a
transparent pixel. The palette is a mapping, or one string of character=color pairs.
What source is decides what is made:
- Text with a newline, or a list of rows: pixel art painted with
palette. - Text without a newline: the name of a registered art or image (see
symbols); you get a copy of the art, or the pixels of the image. A one-row picture is a list,draw(['GG'], palette), so that a call never changes meaning because a symbol was registered later. - An
Imageor a picture fromxnano.image: its pixels are copied (the first frame of an animation). bytesof red, green, blue and alpha, withwidthandheight.None: a blank world ofwidthbyheightpixels filled withbackground.
Parameters:
-
source(str | Sequence[str] | Image | TerminalImage | bytes | bytearray | None, default:None) –What to draw.
-
palette(Mapping[str, ColorValue] | str | None, default:None) –The color of each character of text rows, as a mapping to names,
'#rrggbb'strings or(red, green, blue)tuples, or as a string such as'R=#e03040 G=green'. -
width(int | None, default:None) –The width in pixels of
bytesor of a blank world. -
height(int | None, default:None) –The height in pixels.
-
background(ColorValue | None, default:None) –The color behind the art. Transparent pixels show it.
-
symbol(str | None, default:None) –A name to register the art under, so
draw('name')returns a copy of it. -
effects(Sequence[RenderableEffectSpecification], default:()) –Effects to start on the placement when the art is written, as dictionaries with a
kindkey.
Raises:
-
ValueError–The rows are empty or differ in length, the palette or a color in it is not valid, a text without a newline is not a known symbol, or the sizes do not match the bytes.
-
TypeError–sourceis not one of the kinds above.
Examples:
import xnano
heart = xnano.draw(
'''
.RR.RR.
RRRRRRR
.RRRRR.
..RRR..
...R...
''',
'R=#e03040',
)
assert (heart.width, heart.height) == (7, 5)
print(heart.render())
xnano.draw(['G'], {'G': 'green'}, symbol='grass')
assert xnano.draw('grass').width == 1
Source code in xnano/art.py
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 | |