Sprites

Primitives


Up till now, we've been rendering things using the canvas drawing primitives, such as lines, rectangles, arcs and
(potentially) direct pixel drawing.

These primitives certainly have their uses, but most
in-game graphics are in fact "pre-drawn" in the form of
images (or, in 3D, textured triangles) which are simply
copied onto the screen at the appropriate locations.

Sprites


In the early days of games technology, this process was often accelerated by special "sprite drawing" hardware.

The purpose of the sprite hardware was to implement fast drawing to the display, especially on systems which didn't have enough memory (or enough CPU-power) to drive
a full pixel-level frame-buffer of the kind we use today.

SNES


For example, the Super Nintendo (SNES), as launched in 1991/1992, used this kind of hardware, where the screen was composed of a grid of "background" tiles, with a number of independently controllable sprites superimposed on top.

This mapped pretty well to the sort of games people were making back then, although the relationship was of course
a two-way street (i.e. what people did was influenced by
what the hardware could support!)...


Which is why SNES games all looked kind of like this:


BLIT


In more general, frame-buffer based systems, there has sometimes been another form of "hardware acceleration" to help with the copying of images from one buffer to another and, in some cases, to perform compositing operations
while doing so e.g. supporting transparency.

This approach is known as "bit-blitting" or just "blitting", which sort-of means "BLock Image Transfer"
(though this etymology has been debated).

The Xerox Alto


The origins of blitting go back to the GUI of the Alto,
developed at Xerox PARC (Palo Alto Research Centre)
in the 1970s.

...where pretty much everything else about the modern computing experience was also invented,
by Alan Kay et al. ...as I keep saying ;-)

The Alto version was a software routine called BitBLT,
which was later embedded into micro-code to,
in a sense, "put it into hardware"...

Didn't you get the memo?


Here is the original Xerox PARC  memo describing it.

And here's the famous 1981 "BYTE" magazine article
about Smalltalk, which provides more context.

Later, home-computer systems, such as the Commodore Amiga (1985), and some versions of the Atari ST (1986+)
had dedicated "blitter chips" serving the same purpose.

Those machines were awesome.

PCs

Yuck!

However, most systems (including the "IBM PC") didn't have such dedicated hardware --- but they did had have just about enough CPU power, relative to their screen resolutions,
to support a software only approach...

Today, equivalent operations are often done through the dedicated "GPU"s in the graphics card, typically by
treating a "blit" as the drawing of two front-facing
triangles with a suitable texture pattern on them.

Sprites vs BLITs


The big difference between hardware sprites and BLITs is that the former behaves like an overlay (e.g. a mid-ground sprite-plane in front of a background layer, say) whereas the latter is a direct frame-buffer manipulation with no innate notion of layering (just the one implied by the drawing order).

Destructive!


In particular, a BLIT operation "destroys" the background behind it, which then needs to be restored (typically)
when the object moves elsewhere.

Tracking all of this can add a significant amount of
complexity to things (imagine doing PONG that way!),
unless one simply "gives up" and decides to draw each
frame "from scratch" onto an initially empty surface...

And Yet...


Nevertheless, the blitting approach is
the one adopted in most modern systems,
in part because it is more flexible overall.

Sprite systems tend to have fixed limits
over the number of sprites they can draw,
and tend to be designed for situations in which
the background plane is rigidly grid-like.

Web Browsers


Web browsers handle images using dedicated image-file formats of the type I'm sure you're all familiar with
(.bmp, .gif, .jpg, .png, etc).

The canvas API can tap into that and provide some
sprite/blit-like facilities which operate on them.

The key to all this is the drawImage method...

Using drawImage


drawImage exists in multiple forms, the most general
of which supports arbitrary clipping and scaling.


The messy multi-parameter overloading is,
in my opinion, unfortunate.

What would have been wrong with drawSubImage?

Generalise drawImage

Here's a nice illustration of the most general case:

It doesn't have a built-in rotation param, but we already
know how to do that ourselves with matrix magic! :-)

Async Loading


It's important for browsers to load images asynchronously
i.e. "in the background, without actually waiting for them".
(This was the big innovation of the Netscape browser.)

Without async image loads, perceived page load times would be much slower, because you'd have to wait for each image element to be fully loaded, in sequence.

With async, you typically get to see the text before the graphics, and the images then flow into the page,
having been requested largely "in parallel".

Games?


Async loading is great for typical web-pages,
but it's actually a bit of an annoyance for games.

We don't want our in-game images to be subject to "random" async delays, which might cause them to be invisible for some period after we have initially chosen to "load" them,
and we want to catch errors early too.

In short, we need to pre-load our images somehow…

Homework Pt 1.


Implement a "Sprite" type.

Provide a constructor that takes an Image object defining
the sprite, and add a drawCentredAt(ctx, cx, cy, rotation)
member function which renders the sprite via the specified context, at the given centre-coords, and at the desired
angle of rotation (in radians).

Use this sprite to render a simple "spaceship" object,
and implement a mouse-handler which sets its position
to that of the most recent mouse-click.

Framework


I'll give you a basic framework, derived from last week's PONG example, which also includes a little image
pre-loading helper to get you started.

You also need to implement a "wrap-around" rendering method, which may require a bit of extra thought.

We will use the additional features of this framework in
Part 2 of the homework, so try not to mangle it...

Sprites

By Pat Kerr

Sprites

  • 3,296