Ok, I got the hero to change directions based on user input. Now it’s time to move her. The first step for this is to have a hero_moving flag that the input handler will set if there is d-pad input:
hero_moving: .res 1
handle_joypad:
lda joypad1
and #$F0
beq @end
lsr
lsr
lsr
lsr
tay
lda direction_change_table, y
sta hero_direction
lda #$01
sta hero_moving
rts
@end:
lda #$00
sta hero_moving
rts
With this updated input handler, the hero_moving flag will be 1 when the d-pad is pressed, and 0 when it is not. And as before, our hero’s direction will be stored in hero_direction.
Next, I need to check the hero moving flag in my update_hero_sprite routine, which is called every frame:
update_hero_sprite:
lda hero_moving
beq @hero_moving_done
jsr move_hero
@hero_moving_done:
;...
;write sprite data to RAM as before
Now that I have the foundation laid, I need to write the move_hero routine.
move_hero
There are 8 possible directions the hero could be facing. The current direction is stored in a variable called hero_direction. The possible values for this variable are 0-7, as assigned by these constants:
;direction indexes for tables
SPRITE_UP = $00
SPRITE_DOWN = $01
SPRITE_LEFT = $02
SPRITE_RIGHT = $03
SPRITE_UP_LEFT = $04
SPRITE_UP_RIGHT = $05
SPRITE_DOWN_LEFT = $06
SPRITE_DOWN_RIGHT = $07
I need to alter the hero’s coordinates based on the direction the player is moving. If they are moving left, I need to subtract from hero_x. If they are moving right, I need to add to hero_x. If they are moving up, I need to subtract from hero_y. If they are moving down, I need to add to hero_y. If they are moving diagonally, I need to update both hero_x and hero_y. There are many possibilities, and rather than have a million branch instructions, I’ll use table lookups again. I will have one table for horizontal movement and one table for vertical movement. I will index into these tables using hero_direction. The tables look like this:
;up, down, left, right, up_left, up_right, down_left, down_rt
hero_movement_x:
.byte $00, $00, $FF, $01, $FF, $01, $FF, $01
hero_movement_y:
.byte $FF, $01, $00, $00, $FF, $FF, $01, $01
My move_hero routine will read from these tables and add to the hero coordinates. Note that adding $FF to a number (on an 8-bit system) is the same as subtracting 1, since it will wrap around from $FF to $00. Here is move_hero:
move_hero:
ldy hero_direction
lda hero_movement_x, y
clc
adc hero_x
sta hero_x
ldy hero_direction
lda hero_movement_y, y
clc
adc hero_y
sta hero_y
rts
And now she’s moving.
miau pointed out in a comment that diagonal movement should really alter x and y by SQRT(2) rather than 1 (see Pythagorean Theorum). This is something I didn’t consider before, so my hero covers ground a little more quickly when moving diagonally. I’m not sure yet if this is undesirable behavior or not. If I keep it a simple maze-solving game, it probably won’t be an issue. If I get more ambitious and change it to a more action-oriented game with enemies (something I’ve been seriously thinking about), it may be an issue. We’ll see :).
Animation
I want to talk very briefly about animating the sprite. To do animation, I need a few things:
- Graphics for the various frames of animation
- A counter to tell me when to change animation frames
- A variable telling me the current animation frame
I already have the graphics for my test sprite. The other two I need to make myself.
frame_counter: .res 1
hero_anim_frame: .res 1
The animation is a walking animation, so I don’t want the hero to animate unless she is moving. It makes sense then to do the animation frame-changing logic in the move_hero routine. The Guardian Legend hero sprite has a 4-frame walking animation, so here’s how I do it:
move_hero:
ldy hero_direction
lda hero_movement_x, y
clc
adc hero_x
sta hero_x
ldy hero_direction
lda hero_movement_y, y
clc
adc hero_y
sta hero_y
inc frame_counter
lda frame_counter
cmp #$0B ;change anim frame every 11 "moving frames"
;found this number by trial and error
bcc @end
lda #$00
sta frame_counter ;reset counter
inc hero_anim_frame ;go to next anim frame
lda hero_anim_frame ;make sure we stay between 0 and 3
and #$03
sta hero_anim_frame
@end:
rts
Then I will modify my CHR tile lookup tables to handle graphics for all four frames of animation for all 8 directions. Then I will update my update_hero_sprite routine to read from these tables based on the values of hero_anim_frame and hero_direction. I’m not going to post the code, because it’s a little long and there are a lot of tables. If anybody wants me to elaborate more, let me know in the comments :)
BTW, before I forget! When adding new variables, it’s a good idea to initialize them. Here is my updated initialize_hero_sprite routine:
initialize_hero_sprite:
lda #$50
sta hero_x
sta hero_y
lda #$00
sta hero_moving
sta hero_anim_frame
sta frame_counter
lda #SPRITE_DOWN
sta hero_direction
jsr update_hero_sprite
rts
Conclusion
Whew. I covered a lot of ground today. I probably should have made this two posts instead of one, but I want to hurry up and get to collision detection so I can put up the next demo video. :)
You may have noticed by now that I use hero_direction a lot to index into lookup tables. This is because everything changes based on the hero’s direction, and lookup tables are a great alternative to long sections of compare/branch code. Often when I find myself writing a lot of branching code I’ll see if I can come up with some scheme to turn the test value into a table index.
See you next time!

This is definitely the kind of thing I need to implement. I’ve been including all parts of movement into the actual control routines instead of a using a flag to set when the character movement routine should happen. That’s good enough for smaller projects, but your way makes alot more sense for bigger endeavors, I think. Great post!
@Rob: Thanks! I like to separate the different pieces/components of my program as much as possible. Each piece does its own thing with its own data and that’s it. Then the different pieces communicate with each other with flags. Makes it a lot easier to read the code. And spot bugs too.
Actually, I think I should use separation more than I do. ca65 has a lot of cool scoping features that I don’t use at all because I’ve been too lazy to read up on them. Reading through the source code for Neotoxin made me realize what I’m missing though. Neotoxin was written for a different assembler, but I think they have a lot of the same features.
Oh man, tell me about it! I was looking through that code before and was just blown away! There are so many files, and you have to do alot of bouncing around back-and-forth to see what is going on. It works really well, though, so it’s definitely put together thoughtfully, it seems.
@Rob: When I first looked through it it was a real head-scratcher. I keep going back to it though just to get a look at other approaches and the more I read it the more sense it makes.