Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"Best practices" for animating sprites in Apple II Assembly? (HGR/HGR2)

891 views
Skip to first unread message

jamesiw...@gmail.com

unread,
Oct 15, 2015, 10:15:07 PM10/15/15
to
My family had an Apple IIe when I was young, but the furthest I got in game programming on the Apple IIe as a kid (age 6-13, after which I migrated to C++ programming on Windows PC's) was animated text games in the upper-left corner of the screen (because the Apple IIe didn't animate fast in BASIC and I couldn't find a book that explained Apple II assembly graphics programming in a way that I could understand at the time). I am now getting into Apple II assembly programming on the Apple IIe emulator, AppleWin. I am using the Merlin assembler, and have learned a lot of what I know so far from "Programming the Apple II in Assembly Language" by Rodnay Zaks, which I bought a hard-copy of on Amazon. I'm wondering, I have not seen any commands in the Assembly language instruction set that can put values into an address in memory that is specified by a 2-byte "variable." The closest I see to that is specifying a static 2-byte address, which can take a 1-byte "variable" offset, which I think can be accomplished with STA, if I correctly understand the instruction set. If you only have 1 byte of variability with STA, and in Apple IIe hi-res games, a sprite moves all around a screen that spans 8,192 bytes, what is a typical way that a game programmer would plot pixels to the screen for animation in assembly language? I already understand how screen memory is mapped on the Apple IIe, and how a particular byte will display a particular 7-pixel pattern, so I don't need an explanation of that. (I created a program in C# .NET that spits out all of the starting address for each row in hi-res page 2 memory, according to a formula from Rodnay Zaks' book.) It seems to me that 1 byte of variability in the offset would only allow you to plot to 256 bytes of memory dynamically, and if you wanted to plot to more, you would have to jump through a lot of hoops in order to do so. So, is there an assembly language instruction that I am not aware of that allows 2 byte variability? And, if not, what techniques did (or do) Apple II assembly language programmers typically use to accomplish animation where sprites move all around the screen, which provide an optimum balance of both memory storage and processing speed? I would really appreciate if anyone would answer this question for me, as I haven't yet found an answer to this on the internet and I really want to know how to do it, preferably in a way that would be recommended for best coding practices given the available instruction set. Thanks.

Michael J. Mahon

unread,
Oct 16, 2015, 2:58:20 AM10/16/15
to
It helps to think of page zero as 128 2-byte registers. Many data
manipulation instructions have an "indirect, indexed" form, in which the
instruction specifies the low-order byte of a 16-bit pointer on page zero,
and the effective address is the sum of that address and the Y register.

This is a commonly used way to address all of memory with dynamic addresses
and offsets.
--
-michael - NadaNet 3.1 and AppleCrate II: http://michaeljmahon.com

mmphosis

unread,
Oct 16, 2015, 3:03:33 AM10/16/15
to
Lots of hoops and unrolled loops.

You only need an offset of 40 bytes to span the screen horizontally so this
can be accomplished using an 8-bit index register. You can use a look up
table, like you created with C#, to span the screen vertically 192 lines.

> So, is there an assembly language instruction that I am not aware of that
> allows 2 byte variability?

You can usually only modify one byte at a time with the 8-bit 6502, although
the JSR instruction pushes two bytes at a time onto the stack. The 16-bit
65816 allows 2 byte variability. If you want to modify two bytes using the
8-bit 6502, use two store instructions. Indirect addressing might also be
helpful, although absolute addressing is faster.

LDY horizontal
LDX vertical
LDA lo,X ; lo is the lo order address of the lookup table
STA zp
LDA hi,X ; hi is the hi order address of the lookup table
STA zp+1
LDA (zp),Y
AND mask
ORA shape
STA (zp),Y

Only redraw the parts of the background that need to be "undrawn." Redraw
each animated sprite at it's new location. Flip the page during the
Vertical Blanking Interval.

There are many techniques depending on what type of animation is being done:
sprite animation, tiling, scrolling, color animation, rotoscoping, etc...
Some of Bill Budge's work was mentioned recently. The source code for
Prince of Persia is available.



Anton Treuenfels

unread,
Oct 16, 2015, 9:32:48 AM10/16/15
to
You might start by working out for yourself, on pencil and paper, a formula
to convert an (x,y) location - the actual way you'll likely be thinking of
your sprite positions, as it's by far the easiest - into the address of the
byte on the screen that represents that location. Then think about how you'd
go about converting that formula into assembly language.

Whatever formula you come up with will likely involve a multiplication. The
6502 does not have a multiplication instruction, but you can write a routine
to do it using the instructions it does have. Put the result into a pair of
zero-page locations and you have a pointer to the exact byte you need to
change.

That will work, but it will be slow. If that's a problem for what you have
in mind, consider that you can have Merlin do multiplications at assembly
time. A common approach is to create a table of 192 pointers to the start of
each of the 192 screen lines. Use the y-coordinate to index this table and
copy the result to a pair of zero-page locations. Now use the x-coordinate
to index the byte on that line you need to change using the zero-page
pointer to the first byte on that line.

Both indices are less than 256, so that limit on index register values is
not a problem (split the line pointer table into upper and lower halves to
make it easy to access).

- Anton Treuenfels


<jamesiw...@gmail.com> wrote in message
news:3dfeb2b4-f124-40fe...@googlegroups.com...

John Brooks

unread,
Oct 16, 2015, 11:08:48 AM10/16/15
to
On Thursday, October 15, 2015 at 7:15:07 PM UTC-7, jamesiw...@gmail.com wrote:
> My family had an Apple IIe when I was young, but the furthest I got in game programming on the Apple IIe as a kid (age 6-13, after which I migrated to C++ programming on Windows PC's) was animated text games in the upper-left corner of the screen (because the Apple IIe didn't animate fast in BASIC and I couldn't find a book that explained Apple II assembly graphics programming in a way that I could understand at the time). I am now getting into Apple II assembly programming on the Apple IIe emulator, AppleWin. I am using the Merlin assembler, and have learned a lot of what I know so far from "Programming the Apple II in Assembly Language" by Rodnay Zaks, which I bought a hard-copy of on Amazon. I'm wondering, I have not seen any commands in the Assembly language instruction set that can put values into an address in memory that is specified by a 2-byte "variable." The closest I see to that is specifying a static 2-byte address, which can take a 1-byte "variable" offset, which I think can be accomplished with STA, if I correctly understand the instruction set. If you only have 1 byte of variability with STA, and in Apple IIe hi-res games, a sprite moves all around a screen that spans 8,192 bytes, what is a typical way that a game programmer would plot pixels to the screen for animation in assembly language? I already understand how screen memory is mapped on the Apple IIe, and how a particular byte will display a particular 7-pixel pattern, so I don't need an explanation of that. (I created a program in C# .NET that spits out all of the starting address for each row in hi-res page 2 memory, according to a formula from Rodnay Zaks' book.) It seems to me that 1 byte of variability in the offset would only allow you to plot to 256 bytes of memory dynamically, and if you wanted to plot to more, you would have to jump through a lot of hoops in order to do so. So, is there an assembly language instruction that I am not aware of that allows 2 byte variability? And, if not, what techniques did (or do) Apple II assembly language programmers typically use to accomplish animation where sprites move all around the screen, which provide an optimum balance of both memory storage and processing speed? I would really appreciate if anyone would answer this question for me, as I haven't yet found an answer to this on the internet and I really want to know how to do it, preferably in a way that would be recommended for best coding practices given the available instruction set. Thanks.

One of the the key ideas for fast sprite drawing is to precompute your sprite bitmaps into a 'shifted' format where each sprite frame is stored 7 times, with each version representing one of the 7 starting pixel offsets within a hires screen byte.

You'll want a lookup table which converts your sprite object's onscreen Y position to the hires line's base address (the table you already built with C#), and you'll want to build two more tables which converts an object's onscreen X position to a 0-39 byte offset into the line (ie X/7), and a 0-7 pixel shift so you can select which preshifted sprite image to blit (ie, X mod 7).

Then you'll want an unrolled loop of LDA/AND/OR/STA to blit(draw) bytes from your preshifted sprite data to the screen using the base address from your Y table lookup.

If your sprites are solid (ie tiles) or have large interior areas which are filled, you can have a fast-path blit routine which skips the AND/OR masking step and just does a series of LDA/STA to move the sprite data to the screen.

Hope that helps,
-JB

jamesiw...@gmail.com

unread,
Oct 16, 2015, 11:34:30 AM10/16/15
to
Thanks, everyone, for your answers.
I just found out about indirect indexed addressing, using 16-bit pointers, last night after I posted this message, when I was reading the book by Rodney Zaks. I'm going to try using the indexed addressing first, and see if it is efficient enough for the game I'm trying to make.
Message has been deleted
Message has been deleted
0 new messages