Axcho's Overview of BASIC Sprite Techniques


-------------------------------------------

Output()
--ASCII characters
--Blink characters
Text()
--ASCII characters
--Blink characters
--Textsprites
pxl-Change(), pxl-On(), pxl-Off
--Static Pixelsprites
--Variable Pixelsprites
Plot1(), Plot2(), Plot3()
--Plotsprites

So, I will start from the top.

The simplest way is to use Output() to draw an ASCII character at a specific location on the homescreen. The advantage of this is that it is fast, simple, and can be used in conjuction with a sub() command to efficiently choose a sprite to draw from a string of characters. It also can be used with strings to quickly display and scroll maps. The downside is that it is on the homescreen, and the sprites are limited to looking like ASCII characters.

A variation on this is to quickly alternate displaying between two or more characters, to combine the ASCII characters into something more interesting. This way there is an element of grayscale as well. There are, of course, many disadvantages to this, that it is on the homescreen, it is flickery, and it is slower. I have never seen this technique implemented before, but I think it could be useful in some cases.

A similar method to Output() is to use Text(), which is like Output() except on the graphscreen. This means that you can place the text on any pixel location, and the font is smaller. So both the previous methods apply here, except for the scrolling maps. Because the font size is smaller, though, your sprite selection is even more limited, and the higher resolution makes it effectively slower.

But there is a very good use for the Text() command. This is what I call Textsprites, a technique that I came upon at this topic: here. It involves displaying a string of characters with Text() in a For() loop. Usually the characters are drawn 1 pixel apart from left to right, so that only the first column of pixels is displayed. The columns are usually 5 pixels high, so this technique is useful for displaying 5x5 sprites. The great flexibility of this technique is that it, like all text commands, can be used in conjunction with a sub() command to easily select one sprite from a list. The main disadvantage is that it is a little slow, because it uses a For() loop. So this technique is especially useful in turn-based games, such as board games, card games, and strategy games. But the speed is not bad when compared with more flexible sprite techniques. Only when compared with plain ASCII characters does it seem slow.

Textsprites are also limited in their height of 5 pixels (though you could display larger textsprites by displaying from bottom to top as well as left to right), as well as the selection of characters. Some 5 pixel combinations are impossible using only the characters that are legal on a TI-83. They are, from top to bottom, 00101, 01011, 10110, and 11001. Others are annoying in that they take a very large horizontal space. There are two: 10100 (x root) and 11010 (squiggly x squared). Most other characters take 3 horizontal pixels and erase the 4th column of pixels. So if you want a grid of Textsprites, the most likely space you will need between each sprite is 1 blank pixel between rows, and 3 blank spaces between columns. Of course, if you manage to use only characters that are 2 pixels wide (plus 1 space) on the edges of your sprites, such as ( or [, then you can put the columns 2 pixels away instead of 3. I will put some Textsprites of mine at the end of this post.

The most common TI-BASIC sprite technique other than using ASCII characters is to use static pixelsprites. That is, using a bunch of pixel commands whose coordinates are hard-coded relative to the sprite's upper-left corner. It is pretty easy to write a program that converts an image into a string of BASIC commands that you can paste into your game. The advantage of this is that it is one of the fastest ways to get a bunch of pixels on the screen. The disadvantages have to do with flexibility. You cannot select a sprite to draw without using slow If statements, which reduces their utility in strategy games. They are probably most useful in arcade games, where there are only a few actors in the game. Usually these sprites use pxl-Change() commands so they may be erased and then drawn to a new location with the same set of instructions.

There are several ways to make displaying static pixelsprites faster. One way is to have a separate movement pixelsprite that erases part of the sprite from one end and adds to the other end to make the sprite move in one direction. You would need one of these for each direction that the sprite moves. This is only effective if the sprite moves a small number of pixels each step, though. If your graphics are tile-based, then you will have to use the next technique. The purpose of the next technique is to reduce the number pixels you have to display at a time. You do this by displaying them when the program loads, as the background. I did this in the game Treasure Hunter, which is basically a graphics demo for this method. The player and enemy sprites move on background tiles that look like grass, and they share pixels with the grass so they only have to display about half the pixels that they would normally! To design the sprites, first draw the whole sprite you want, and then pxl-Change() (otherwise known as XOR) the background tile on top of it. Then turn the resulting mush of pixels into a bunch of pixel commands that you can display on top of the background with pxl-Change() to recreate your sprite. This only works for tile-based sprites, though.

An alternative to static pixelsprites is variable pixelsprites. This trades off the speed of static pixelsprites for the greatest flexibility of all sprite techniques. Variable pixelsprites means reading data from a matrix, list, string, or other structure to determine which pixels to turn on or off. The easiest way is to just take a matrix and a couple of nested For() loops and use an If statement to see whether each matrix element is a 0 or 1, and then draw a pixel if it is a 1. However, this is both extremely inefficient and slow. Matrices store each element as an 11 byte real number, so they are overkill for a binary sprite. A much better way to do this is to use a string like in the example below. This both eliminates If statements and uses only one loop, besides taking less memory than a matrix. This example displays a random 5x5 sprite at a random location in a grid on the graphscreen. To make different sized sprites, you will have to change a few numbers in the code.

"O O OOOOOOOOO OO OOOO OOO O OO     OOO O     OO OOO    OO O   OOO   O   O OO    O O   OOOO
OOO O O O O O OOO OO O O OOOO O O OOO OOO O O O O O OOOO O OO OO O
OOO OOOOO OOOOOO O OO OO OO OO O OOO O O


sub(Ans,1+25randInt(0,8),25\->\Str1
6randInt(0,9\->\X
6randInt(0,15\->\Y
5-10randInt(0,1\->\Z
Text(X,Y,"    "
inString(Str1,"O",1
While Ans
Pxl-Change(X+iPart(.2Ans-.2),Y+iPart(.5(4-Z))+ZfPart(.2Ans-.2
inString(Str1,"O",Ans+1
End


An interesting sprite technique was introduced recently here. It is plotsprites, displaying a collection of points on a graph using the built-in plotting functions of the calculator. This has the advantage that it is very flexible, where you can easily edit the list of point coordinates in the middle of the program, as well as adjust the graph settings and change the style of the individual points to boxes or crosses. Here is a great example by Sir Robin of using plotsprites in a program.

To use plotsprites, first set the graph window to an appropriate size, usually with one pixel per change in X or Y. Then store the X coordinates to any list, and the Y coordinates to another list. To initialize the plot, fill in the blanks in this code: PlotX(Scatter,XLIST,YLIST,\dot\ You may change the \dot\ to a \cross\ or \box\ if you want to display something other than just pixels. If you do this, you could also modify the graph settings to match the grid of a board game. There are 3 different plots you can use, which gives you only 3 sprites, unless you Augment() several lists of sprites together. To display the plotsprite, use the DispGraph command, and to change all the coordinates simultaneously, just add a single real number to the whole list of coordinates.

Here are a bunch of 5x5 textsprites that I made. I had to make compromises, especially for the chess pieces and medieval units. There are both classic and abstract chess pieces, with the white piece first, then the black.

Assuming that the sprite is stored in Ans, use this code to display them:

Ans+"  "
For(Z,1,length(Ans
Text(X,Y+Z,sub(Ans,Z,1
End


Note: Whatever is between two backslash characters is a name, not the actual character. 
This is how graphlink exports program files to text. For example, \cross\ is the little +
 character. Also, \^x\\root\ is a single token, as is \chi\\^2\ (that's what the squiggly x
 is called).


SMILE
"\cross\).)\cross\

FROWN
".\^2\\cross\\^2\.

WINK
":S.)\cross\

TONGUE
"-\^x\\root\e\>=\e

GRIN
"e2/2e

EVIL
"\^2\S.S\^2\

ANGRY
"):\cross\:)

SLEEP
"T\(-)\)ST

HAPPY
":)\(-)\T\(-)\

DRY
"\chi\\^2\) YT

UNSURE
" T.\^2\\cross\

COOL
"Y\chi\\^2\)YY

SPADES
"e([(e

HEARTS
"v\^2\S\^2\v

DIAMONDS
"-:):-

CLUBS
"eQ[Qe

PAWN
" s2s
" s[s

KNIGHT
"v\i\\>=\)(
"\(-)\!X[(

BISHOP
".A\^2\A.
".AQA.

ROOK
"YAYAY
"YA[AY

QUEEN
"\(-)\\box\Y\box\\(-)\
"\(-)\\box\[\box\\(-)\

KING
"eS\i\Se
"eX[Xe

P
"()))(
"([[[(

N
"\(-)\\>=\\>=\)(
"v'X[(

B
"/s)s/
"/A[A/

R
"[)))[
"[[[[[

Q
"X\>=\)\>=\X
")X[X)

K
"-:):-
"-([(-

FOOTMEN
"T:'A(

PIKEMEN
"TSeAe

KNIGHTS
"vSeQ\i\

ARCHERS
"(\xbar\\box\(.

CATAPULT
"Ae:X\^2\

CASTLE
"[v[s[

FARM
"\xbar\-\>=\)\xbar\

TREE
"\cross\([(\cross\

ROCK
"(X\>=\2(

PAPER
"[)!\>=\A

SCISSORS
"2:-:2


There are many characters that have the same first column of pixels, and usually it doesn't matter which one you use. But some are wider than others, so you will usually want to use the thinner one. For example, \(-)\ is the same as ^ but the negation sign is thinner. Also, there are sometimes tradeoffs. For example \>=\ (greater or equal to) is the same as \xbar\ but \>=\ is 1 byte and \xbar\ is 2 bytes. The problem with using \>=\ is that it is 4 pixels wide instead of 3, so if you use it at the edge, then you will get an extra column of pixels. So only use it in the middle. You will notice this above.

Here is an example to display a random playing card at the corner of the screen:

sub("e([(ev\^2\S\^2\v-:):-eQ[Qe",5randInt(1,4)-4,5)+" "+sub("A23456789TJQK",randInt(1,13),1
For(X,1,length(Ans
Text(0,X,sub(Ans,X,1
End


It doesn't have two spaces at the end to erase the end because the last character is the rank of the card!

Additional note: Plotsprites are also good for moving lots of little guys at a time, for example, enemy ships. You do any operation on the lists of coordinates as long as the expressions resolves to a real number or a list of the same dimensions.

It can be a simple number, like gravity:
LY-1->LY

It can be a velocity that is common to all the points in the plot:
LX+U->LX
LY+V->LY

It can be a list of velocities:
{1,0,1,-1->LXVEL
{-1,0,1,1->LYVEL
...
LX+LXVEL->LX
LY+LYVEL->LY

It can be an expression that resolves to a list:
LX+(LXX->LX
LY+(LYY->LY

It can be a randomly generated list (slow):
LX+randInt(-1,1,4->LX
LY+randInt(-1,1,4->LY

As you can see, there are lots of possibilites, more than just the ones I've shown here. Also, you can pretty easily test to see if any of the points match up with another point:
max(X=LX and Y=LY



This page can be found in its original form at United TI.

Also check out Axcho's author page over at TI-Calc.org to see his great games and programs!