Editing Sprites in the Editor

T

his week made a return with Darren and me implementing game characters from the Sprite Pad tool.  Siggy was taking a break at this time. So our goals were to take the binary sprites Darren created and add them to the current running project, which includes their animation frames as well.

CBM Prg Studio Sprite EditorUsing the Sprite Editor tool in CBM Prg Studio, we had previously imported the sprites binary data so we could begin editing the sprites generated in Sprite Pad in this environment.  The sprites are 12 x 21 in the Editor. Each sprite frame can be viewed by clicking on the button arrows on the right in the category called Current Sprite. We noticed that the sprite multicolors had not copied to the Sprite Editor, so we started this session updating the sprites.  Multicolors are activated by clicked on the checkbox on the right called Multicolor.

Darren explained next that he used two types of sprites. One was for the shell around the sprite making up the head, arms, and legs. The other sprites created the clothes.  This was done to add extra colors around the sprite.

Sprite Editor Globalize ColoursWe wanted to find a way to copy colors across the sprite. Otherwise we would be forced to set the colors for each individual frame. Under the Sprites menu there is a item called Globalize Colours.  To control all the colors the checkbox for All colours was activated. So after we set this option, the Multicolour checkbox had to be set for each sprite frame.  With some of the sprites, we had to set individual colors to prevent copying over them with the globalize option.

Adding the Sprites to the Project

After setting all the colors, I closed the Sprite Editor window to begin adding the sprites to our current game project.  The command incbin is used to load in binary files. So in Siggy’s project he set it up for the current sprites in use, so we had to modify this to incbin “Sprites.spt”,1,59,true to accommodate the 59 sprites that were edited earlier in this session. There were some issues loading the sprites, so close to an hour into the  video, we commented out the incbin that loaded Siggy’s sprites to get ours on the screen.

The top sprite was controlled by the joystick (gamepad controller) and the bottom sprite was set to an animation sequence. So our goal was figured out how to control the sprite animation frames at the top so we could create an animated sprite as the controller was moved.

We were trying to understand the logic that Siggy developed, so Darren created a side project in his spare time to learn from it. The screenshot seen here extracted the sprites from Siggy’s Trump jump. Darren explained by saying, “There are 3 sprites. The body is 2 sprites, the tie and shirt are one sprite, and blue suit, hands, and feet were another sprite. They are laid on top of one another. The head is also one sprite.”

For the animation, he had the sprite shifting positions from the right to the left, depending on which way the player was moved.  The idle animation made the sprite bounced up and down looking to the left or right. Again this is dependent upon the last sprite position that was retained.  He clarified that the LAST_LOOK verified recalled the last direction the sprite was looking toward. If you study the code sample below, you can gain more of a grip on the logic.

  • @updateAnimation2

  • lda SPRITE_DIRECTION

  • bmi @movingLeft2

  • beq @movingNone

  • ; moving right

  • lda #1

  • sta LAST_LOOK

  • lda #SPRITE_BASE + 4

  • sta SPRITE_0_PTR

  • lda #SPRITE_BASE + 24

  • sta SPRITE_1_PTR

  • lda #SPRITE_BASE + 28

  • jmp @updateAnim2

  • @movingLeft2

  • lda #0

  • sta LAST_LOOK

  • lda #SPRITE_BASE + 0

  • sta SPRITE_0_PTR

If the LAST_LOOK variable is set to 1, then the sprite is looking to the right. Otherwise a zero value placed here, sets the sprite looking to the left.

Sometime later we began working on the animation frames code from Siggy’s project.  Our goal was to figure out which sprite frames moved in the left versus the right direction. Closer examination of the Sprite Editor “killbot.spr” showed that the right frames occupied values 13-16 and left contained the values 17-20. The code below controls the range of movement between these frames. So we changed it to fit our new animation sequence.

  • @left_right

  • clc

  • lda ANIM_FRAME, x ; if the animframe is 12 or more

  • cmp #16 ; moving – so we can just continue

  • beq @left_check

  • lda #19 ; if not we set it to a value that

  • sta ANIM_FRAME, x ;automatically – setting it to the

  • @left_check

  • lda SPRITE_DIRECTION, x ; if direction is -1 we are moving left

  • bmi @movingLeft

  • clc ; Sprite moving right – use frames 3

  • cmp #7

  • bcc @updateAnim

  • lda #0

  • sta ANIM_FRAME, x

  • jmp @updateAnim

There was still a problem with some of the frames so we examined the code further down for movingLeft to make some new changes.

  • @movingLeft

  • ; Sprite moving left – use frames 9-12

  • lda ANIM_FRAME, x

  • cmp #20 ; Check to make sure the anim frame isn’t = 20

  • beq @resetLeft ; Reset to the start frame if it’s overrun

  • clc ; a special case when you go from right to left

  • cmp #16 ; the anim frame will be between 12 – 15

  • bcc @resetLeft ; left alone it will increment up to 16

  • ; which leaves an ugly result

  • jmp @updateAnim

  • @resetLeft

  • lda #16 ; reset to frame start if it overruns

  • sta ANIM_FRAME, x

  • jmp @updateAnim

After an hour and 45 minutes into the video, we started changing the updateAnimation area to reflect the sprite frames updating in the correct order. Earlier we noticed that frames were being skipped, so now we were covering our tracks and patching up this section. Eventually after some trial and error, we got the idle animation working, but were still left with one frame deviating the norm, which involved further evaluation of the code.

  • @updateAnimation

  • inc ANIM_FRAME, x ; move to the next anim image

  • lda SPRITE_DIRECTION, x ; see if we’re standing still – equal would be 0

  • bne @left_right ; if we’re moving – test for left/right direction

  • clc

  • lda ANIM_FRAME, x ; Standing still – we use frames 0 to 3

  • cmp #32 ; if we hit 4 we need to reset to start

  • bcc @updateAnim

  • lda #28 ; reset to start (frame 0)

  • jmp @updateAnim

  • @left_right

  • ; if we go from standing to moving, the frame will be

  • ; very low and will just increment until it hits a max from

  • ; for the other cases – which would be very ugly

We decided to comment out the lines below to see if that would stop the wrong frame from showing up when the sprite was left idle (no controller movement). At this time we were still in the early learning stages of grasping Siggy’s logic and putting into practice.

  • ;clc

  • ;lda ANIM_FRAME, x ; if the animation is 12 or more, we were probably already

  • ;cmp #13 ; moving – so we can just continue with our direction check

  • ;bcs @left_check

  • ;lda #20 ; if not we set it to a value that both cases will correct

  • ;sta ANIM_FRAME, x ; automatically – setting it to the correct start frame

  • @left_check

  • lda SPRITE_DIRECTION, x ; if direction is -1 we are moving left

  • bmi @movingLeft

  • ; Moving right

  • clc ; Sprite moving right – use frames 3-7

  • lda ANIM_FRAME, x

  • cmp #7

  • bcc @updateAnim

  • lda #0 ; reset back to start frame

  • sta ANIM_FRAME, x

  • jmp @updateAnim

How to create Sprite Pad Animations

SpritePad AnimatiDarren setup Sprite Pad to automatically animate the sprites by individual frames. This is done by clicking on a sprite in the bottom window in clicking on the play (right arrow) button in the editor. To add an additional animation you have to increase the Quantity category to make room for more. This will insert blank spaces in the bottom window. It was set to 32 so I increased it to 35. Next it I selected a range of sprites in the top right. Then also in top window he stated to click the last icon with the description of Send range to Animator. That feeds the sprites frames into the empty square and allows the frames to be set in an increased motion, which resulted in animation.

Our next primary goal was to add in our second overlay sprite. The sprite frame pointers are identified by the variables below.

  • SCREEN_MEM $4000 ; Bank 1 screen 0

  • SPRITE_POINTER_BASE = SCREEN_MEM _ $3F8 ; last 8 bytes of screen mem

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 0

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 1

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 2

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 3

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 4

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 5

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 6

  • SPRITE_0_PTR = SPRITE_POINTER_BASE + 7

After this, we began modifying the sprite pointers that existed before. Darren stated that since we didn’t have a need for SPRITE 1_PTR since it was tied to the running sprite, which gets overwritten since the sprite moves backward and forward at the bottom automatically. On primary focus was to change the data for the top sprite. So commented out some code and added the SPRITE_2_PTR statements below.

  • lda #SPRITE_BASE + 28 ; Take our first sprite image (Killbot)

  • sta SPRITE_0_PTR ; store it in the pointer for sprite 0

  • ; lda #SPRITE_BASE + 32

  • ; sta #SPRITE_2_PTR

  • lda #SPRITE_BASE + 32 ; Our new lines were added here

  • sta SPRITE_2_PTR ; and here

Working on the Sprite Overlay

In order to determine the exact placement of the overlay sprite, Darren suggested to enable SPRITE 2. The code below accepts those new changes. The change was made in the binary values from 00000011 to 00000111. This tracks the active display for sprite 2 (counting 3 from the right to left).

  • lda #%00000111 ; Turn on sprites 0 and 1

  • sta VIC_SPRITE_ENABLE

We added some more code to the moveUp routine to accommodate for our overlay sprite. This works by setting a table for the sprite x location. I have included the lines for the MoveSpriteUp routine so you can also see what the subroutine jump is doing. Essentially it maps the sprite x table to the correct location.

  • MoveSpriteUp

  • dec SPRITE_POS_Y, x ; decrement the sprite position variable

  • txa ; copy the sprite number to A

  • asl ; multiply it by 2

  • tay ; transfer it to Y

  • lda SPRITE_POS_Y, x ; load the sprite position for this sprite

  • sta VIC_SPRITE_Y_POS, y ; send it to the correct VIC register – $D001 + y

dec SPRITE_POS_Y_DELTA, x

  • bmi @reset_delta ; test to see if it drops to negative

  • rts ; if not we’re done

  • @reset_delta

  • lda #$07 ; reset the delta to 0

  • sta SPRITE_POS_Y_DELTA, x

  • dec SPRITE_CHAR_POS_Y, x ; if delta resets, we’ve crossed a character border

  • rts

So all we had to do was add more statements in the moveLeft subroutine. This allows the second (overlay) sprite to occupy the same position as the sprite moved with the controller (the sprite that starts at the top).  We appended new lines in the code to track the movement for right and left movement to position sprite 2 in place.

  • ldx #0

  • jsr MoveSpriteRight ; Joystick X positive – move right

  • ldx #2

  • jsr MoveSpriteRight ; Sprite 2 (overlay)

  • jmp @testUpDown

  • @moveLeft

  • ldx #0

  • jsr CanMoveLeft ; check to see if we can move left

  • bne @testUpDown ; if blocked – no case move that way

  • ldx #0

  • jsr MoveSpriteLeft ; Joystick X negative – move left

  • ldx #2

  • jsr MoveSpriteLeft ; Sprite 2 (overlay)

Our changes resulted in adding a third sprite to the running sprite at the bottom (appearing in blue). We realized our mistake and went back to investigating the code to see where the change the correct code segments to accomplish our goal. However, time constraints preventing us from reaching any milestones beyond this point and we called it a day.