Bitmap animation
Moderator: Moderators
Bitmap animation
I know, i'm a rookie, but I'm trying to learn how I can get a good smooth bitmap animation on the vic. I thought to use the way described on Compute! Magazine (i.e. create a series of u.d.g., each one shifted of one pixel to simulate a bitmap animation). My question is: is this the only way to create smooth animation in basic since it requires the waste of a lot of u.d.g.?
No one should tolerate death and violence because tolerance will generate habit.
I believe the thread you want to read is software sprites initiated by rhurst. Of course it requires you to at least party work in machine code, ideally using the ca65 assembler. The idea behind software sprites is to allocate a few user-definable characters and copy another graphic into them, dynamically shifted as you go.
Perhaps it would be possible to add a Basic API to the library, at least so you can set up sprites and get them animated by a series of SYS calls or similar.
Perhaps it would be possible to add a Basic API to the library, at least so you can set up sprites and get them animated by a series of SYS calls or similar.
Anders Carlsson
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Bitmap animation
At least three ways spring to my mind here:Ivanhoe76 wrote:i.e. create a series of u.d.g., each one shifted of one pixel to simulate a bitmap animation ...
1. All shifted specimen within the actual character set,
2. Some (e.g. 2 or 4) characters dedicated to the sprite, and copying from a set of pre-shifted data outside the actual character set, or
3. Only holding an un-shifted definition, computing the shifted sprite data on-the-fly.
While the 1st method occupies the most place within the "live" character set, it's also undoubtedly the fastest, since you only need to POKE 2 or 4 characters in screen RAM to move the figure by one pixel. It might even be viable from BASIC, as the article in Compute! suggests.
The 2nd, and 3rd method are only viable with ML, as you'll at least need to copy 16 or 32 bytes, let alone rotate them in place. The 3rd method essentially is the one used by Robert's Software Sprite Stack.
In MINIPAINT, I use a variant of the 2nd method to provide the cursor. The cursor does not need to be positioned at every pixel position within a char, but the hires cursor takes 4, and the multicolour cursor takes 2 different positions within a 3x2-character grid.
Greetings,
Michael
Will you want objects to meet, i.e. a character walks straight into a wall? In that case the first method is unsuitable.
You also need to keep track which frame you have displayed, as the character may take 1-4 squares in possession depending of position. You can avoid this by defining two to four characters for each frame, depending on whether the character moves horizontally, vertically or both.
At worst, you may end up with 8*8 = 64 pre-defined custom characters just to animate one 8x8 pixel object. That is 512 bytes of mostly waste.
The second method is slightly better, but not by much. At least you could OR two different patterns into place to make things meet.
I believe a Basic API for the sprite stack is the most flexible and in the long run most memory conservative approach.
You also need to keep track which frame you have displayed, as the character may take 1-4 squares in possession depending of position. You can avoid this by defining two to four characters for each frame, depending on whether the character moves horizontally, vertically or both.
At worst, you may end up with 8*8 = 64 pre-defined custom characters just to animate one 8x8 pixel object. That is 512 bytes of mostly waste.
The second method is slightly better, but not by much. At least you could OR two different patterns into place to make things meet.
I believe a Basic API for the sprite stack is the most flexible and in the long run most memory conservative approach.
Anders Carlsson
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Or you can mask out parts of the background, and then OR in the data in a second step, so a pixel of the sprite definition is either transparent or is one of 2 or 4 colours - depending whether it is hires, or multicolour.carlsson wrote:The second method is slightly better, but not by much. At least you could OR two different patterns into place to make things meet.
Providing pre-shifted data instead of constructing that data on the fly is one example of the space-vs-time trade-off. And then there's also the 'ease-of-implementation' issue.I believe a Basic API for the sprite stack is the most flexible and in the long run most memory conservative approach.
I don't think we've even addressed collisions yet.
Space vs time.. that's true, I had forgotten most VIC-20 users these days have at least 8-16K expansion memory, many even have 32K in one form or another. Since Ghislain just released a great 32K game, chances are that even more people will get themselves a good memory expansion which also lets other developers trade bytes for raster lines.
Space vs time.. that's true, I had forgotten most VIC-20 users these days have at least 8-16K expansion memory, many even have 32K in one form or another. Since Ghislain just released a great 32K game, chances are that even more people will get themselves a good memory expansion which also lets other developers trade bytes for raster lines.
Anders Carlsson
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Just for fun I made a quick byte poll. The cursor display in MINIPAINT uses:
- 288 bytes for 6 shifted copies of the cursor @ 48 bytes each,
- 66 bytes for pre-calculated address tables, and state data,
- 273 bytes for code contained in 3 sub-routines.
Not counting the calls from the main program into these sub-routines. Together 627 bytes.
Here's the sub-routine, which updates the cursor display, i.e. makes it blink. Register A contains the desired colour source on entry:
To display the cursor, characters 122 .. 127 in the character set beginning at $1800 are used, i.e. $1BD0 .. $1BFF.
- 288 bytes for 6 shifted copies of the cursor @ 48 bytes each,
- 66 bytes for pre-calculated address tables, and state data,
- 273 bytes for code contained in 3 sub-routines.
Not counting the calls from the main program into these sub-routines. Together 627 bytes.
Here's the sub-routine, which updates the cursor display, i.e. makes it blink. Register A contains the desired colour source on entry:
Code: Select all
.C:4da3 85 F9 STA $F9
.C:4da5 AD E7 4C LDA $4CE7 ; get pointer to definition, and copy to ZP $FB/$FC
.C:4da8 85 FB STA $FB
.C:4daa AD E8 4C LDA $4CE8
.C:4dad 85 FC STA $FC
.C:4daf A0 00 LDY #$00
.C:4db1 B1 FB LDA ($FB),Y
.C:4db3 49 FF EOR #$FF
.C:4db5 39 D0 1B AND $1BD0,Y ; clear non-background pixels,
.C:4db8 85 FA STA $FA
.C:4dba B1 FB LDA ($FB),Y
.C:4dbc 25 F9 AND $F9 ; apply colour source to cursor data,
.C:4dbe 05 FA ORA $FA ; merge into background data, and store.
.C:4dc0 99 D0 1B STA $1BD0,Y
.C:4dc3 C8 INY
.C:4dc4 C0 30 CPY #$30 ; loop over 48 bytes
.C:4dc6 D0 E9 BNE $4DB1
.C:4dc8 60 RTS
Last edited by Mike on Fri Oct 23, 2009 3:46 am, edited 1 time in total.
- Mike
- Herr VC
- Posts: 4841
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
If you arrange the destination character bytes on screen in column-major order, there's no need to store different versions for vertical displacements. You'll just have to pad the definition at the top with up to 7 zero bytes, and begin reading with 0 to -7 bytes offset from the original start to shift down the result.
That's a space optimisation I didn't do in the cursor display yet. It would save me maybe around 100 bytes. But that still wouldn't allow the program to work with a +8K expansion only.
That's a space optimisation I didn't do in the cursor display yet. It would save me maybe around 100 bytes. But that still wouldn't allow the program to work with a +8K expansion only.
Last edited by Mike on Fri Oct 23, 2009 3:59 am, edited 1 time in total.
Do you have a prototype game using traditional character graphics? Otherwise perhaps you should begin there, and convert it to smoother graphics later on. I imagine one needs to keep track of virtual coordinates of a high resolution screen to practically solve collisions. Perhaps several sets of arrays which have the indexes intact:Ivanhoe76 wrote:There's too much I still have to learn about programming...
DIM O$(20),X(20),Y(20),T(20)
X and Y would keep track of virtual coordinates. T would have a numerical value for what kind of object it is: enemy, bullet, dangerous or ignorable object. O$ may be used to name objects if needed. Some of these could be put in a multi-dimensional array but I think it takes more memory. You could also store the numerical values directly into memory using PEEK and POKE instead of using variables.
When something moves, you check the screen matrix as usual. As soon as two objects get within the same 8x8 square, you need to decide whether they can co-exist and how close they can get by calculating the virtual coordinate and determine which object it may be you encountered. This can get problematic if more than two objects occupy the same square.
Anders Carlsson