Sprites in Basic II - Animation

Updated for Emulator R.37+

As we move forward with game design and development the focus shifts to game play and graphics and less on actual coding. Sure, coding is the glue that makes everything run smoothly and that overall experience is pleasant but the appearance is becoming more and more central point. I am not a professional by any means but I personally actually enjoy this part of game design just as much as coding, which is fortunate. Too often I see perfectly coded games (or other software and apps) with mediocre graphics and design.
We will therefore first create graphics for our sprite and then write the code after we know what we are working with.
The goal is very simple, let’s create a character that we can move or walk around the screen. Let’s also minimize the amount of typing and go for simple 16 x 16 sprite.

Sprite development

I am using several tools to draw pixel art, for more complex stuff I use tablet pad and Krita but for simple stuff I will just use Paint.NET and Aseprite for animation.
We will do a simple person, let’s call him “Sam” (After an underwater game I was working on but never finished "Scuba Sam"). At 16 x 16 pixels we can’t really shoot for realism so let’s make him cartoonish with head occupying about half of the sprite. Therefore we have only few pixels remaining for the rest of the body:



It is very simple really, the head is slightly oval as we are watching from top down, legs and arms and two eyes.
For animation we will again simplify things and use four frames for a full cycle. Again the only thing we need to do is animate legs and to make a bit more real also some arm movement. For walk down the frames can be as follows:


We will use standard palette to color our hero. We will give him brown hair, blue jeans pants and bright orange shirt today. The above four frame animation now looks like this:


For walking up the screen we can use the same outlines, we just need to cover the head with hear. To make it a bit less uniform we will add few darker strains of hair. The animation sequence looks like this:


Side view is usually a little harder for some reason, but I think this will do just fine:


So all needed images are collected on following Sprite Sheet.


Before we move to coding let’s analyze the Sprite Sheet and try to identify redundancies with the goal to reduce memory space required and not affect the speed too much. This is very common dilemma in game development speed vs space and we will be dealing with it much more in the future when we will be working on more complex projects.
As we see we have sprites for 4 directions and 4 to perform full walk cycle. However there are some clear duplicates:

  • Every first and third sprite in sequence are the same – so we can eliminate 4 sprites
  • Every second and fourth sprite are mirror images of each other. Since we have register for flipping sprite horizontally we can eliminate those 4 too
  • And last the whole fourth row is mirror image of third row (walking left and right) so we can eliminate those as well. That is additional two sprites eliminated (we shouldn’t count two twice)
So we only need to define 6 sprites out of 16 to draw all needed frames of animation. Of course that will require some code but it shouldn’t be too complex. This will save precious Video RAM and speed up initialization phase.

Transfer graphics into code

In part one of Sprites in Basic we stored actual numbers in DATA section of the program and using simple loop were poking them into memory. We will slightly improve on it. Instead of typing in color codes we will define sprite in 16 strings with each character representing one pixel. Based on the drawings above we will need:
“1” – Black
“2” – Brown
“3” – Dark Brown
“4” – Skin
“5” – Orange
“6” - Blue
Clearly we could use 16 color mode for this sprite and still have 9 additional colors at our disposal but for the sakes of simplicity let’s just use the same mode as in previous chapter. First frame of sprite can therefore be defined as:


Clearly blanks are transparent pixels and other are based on the color code we picked above.  We can fairly quickly type the definitions for remaining five sprites as there is a lot of just copying and pasting. The code to transfer this into VPOKEs is very simple:


In line 30 we initialize variable M which will be our offset into VRAM for VPOKE.
Then we loop 6 times for 6 sprites and 16 times for 16 lines of each sprite. Of course we could do this in single loop.
In line 60 we read string representing one row of pixels in a sprite and then loop through each character.
In line 80 we extract each character and in lines 90-150 determine exact color from palette for that color code. This approach has a very convenient benefit. It allows us to play with different colors and experiment with what works best on certain background. Or we can change color of our hero from level to level by just redefining him/her with different colors. The negative side of this approach is speed. This does take few seconds to process…
In line 140 we store the color index into VRAM starting at address $4000 and increase our memory offset in line 170.
Only thing remaining is closing all the loops in lines 180-200.

Displaying the Animation

In lines 220 – 300 we turn on and initiate the sprite. The process is identical as in Part 1 the only differences are:

  • We are using Sprite 1 and not 0 so we use registers $5008 - $500F instead of $5000 - $5007
  • We set default position at 160 x 100 so the sprite appears roughly at the center of 320x200 mode screen (SCREEN 0)
In lines 510 and 520 we switch to the 320x200 text mode, and set the brown background. We can do that with three PRINT codes: CHR$(149) to set color to brown, then change it to background with CHR$(1) and finally clearing the screen to apply this new color setting to the whole screen.
In line 530 we set some basic variables. Current X and Y position are pretty clear. In addition to those we are also declaring DIR for direction and I for animation Index. Index will just be looping from 0 -> 1 -> 2 -> 3 -> 0 -> 1 and so on. For DIR we picked following values:


Value Direction
0 Up
1 Right
2 Down
3 Left

In order to control all the possibilities we have to organize them all in some way that is easy accessible without much calculation. The last thing we want it so to have ton of IF statement to test for each condition. One way to do is to prepare all options in advance and just pick the right one during the runtime. One way is to use arrays. Since we have two variables that change as we move across the screen and determine the appearance of sprite I used two dimensional array to decide which sprite graphics to use.  We declare it with:
DIM O(4,4)
If we decide that we will use direction of movement for first index and animation sequence as second we can fill in the following data. By data of course I mean the offset for graphic pointer in Sprite data. First one is at offset 0, second at offset 8, third at 16 and so on for all 6 different graphics. Remember each sprite takes uses 256 bytes (16*16) but since 5 lower bits are always 0 so we can address in 32 byte increments so 8 in pointer means we are stepping up by 256 bytes.


Frame\Direction 0 (UP) 1 (RIGHT) 2 (DOWN) 3 (LEFT)
0 16 32 0 32
1 24 40 8 40
2 16 32 0 32
3 24 40 8 40

The above data is stored in array in lines 550-580.


We also have to take the V-flip into consideration and because it is set in separate register it is more convenient to create another two dimensional array instead of one three dimensional. We declared it also in line 540 as DIM F(4,4). With declaring it, BASIC will automatically fill the whole array with zeros so we only need to change the ones that point to sprites that actually need to be flipped. The values should be the following:

Frame\Direction 0 (UP) 1 (RIGHT) 2 (DOWN) 3 (LEFT)
0 0 0 0 1
1 0 0 0 1
2 0 0 0 1
3 1 0 1 1

Now we have everything to make our hero walk around the screen.


In Line 610 we read Joystick which in Emulator from version R35 also returns pressing the arrow keys. We could also use GET command but the difference is that JOY does not rely on keyboard auto-repeat and is therefore more appropriate for this purpose.
In lines 620-650 we simply check which direction we want to go to and increase X and Y by 1. We could change this to 2 or even 3 to make our hero move faster and animation would still look good. We only check if the sprite is moving out of screen at the top and right because that would cause an error. We allow him to walk off on the right and bottom.
In lines 660 and 670 we increase the animation frame index and loop it back to beginning if needed.
Now all that is required to show Sam at the next position is to make few updates:
Line 680 – Update X coordinate using formula from Part 1
Line 690 – Update Y coordinate using same formula
Line 700 – update the pointer to graphics using the above defined array
Line 710 – updating the H-Flip flag making sure we don’t change other attributes in the same register
And at the end go back to beginning of the “Game” loop.
One of the main drawbacks of this approach is slow loading of Sprite graphics into Video RAM. In principle it should be possible to load data directly into it and much faster but I have some difficulties making it work. Not yet sure if I am doing something wrong or if the issue is with the current version of emulator. Will update this post when I figure it out.


Comments

  1. Very nice post! Looking forward to more. Merry Christmas!

    ReplyDelete
    Replies
    1. Thank you Indy, apprecaite the comment. Christmas is over so I wish you and your family all the best in New Year 2020.

      Delete

Post a Comment

Popular posts from this blog

Commander X16 Premium Keyboard

Hello VERA (BASIC vs C vs Assembly)

Default Palette