Displaying Metasprites

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
simseventy
Posts: 5
Joined: Sun Oct 27, 2013 6:17 am

Displaying Metasprites

Post by simseventy »

Hi guys,

I've recently started looking into programming for the NES. So far I've been playing around with sprites and nametables, just trying to get a feel for how it all works.

In one such experiment, I have the following two subroutines:

Code: Select all

create_mario:
	ldx	#$00
	
@loop:
	lda	spriteData, x
	sta	$0200, x
	inx
	cpx	#$10
	bne	@loop
	
	rts

;;;;;;;;;;;;;;;;;;;;;;

create_luigi:
	ldx	#$00
	
@loop:
	lda	spriteData+16, x
	sta	$0200+16, x
	inx
	cpx	#$10
	bne	@loop
	
	rts

;;;;;;;;;;;;;;;;;;;;;;

spriteData:

	.byte	$80, $32, $00, $80 ; mario sprite 0
	.byte	$80, $33, $00, $88 ; mario sprite 1
	.byte	$88, $34, $00, $80 ; mario sprite 2
	.byte	$88, $35, $00, $88 ; mario sprite 3
	
	.byte	$90, $32, $01, $80 ; luigi sprite 0
	.byte	$90, $33, $01, $88 ; luigi sprite 1
	.byte	$98, $34, $01, $80 ; luigi sprite 2
	.byte	$98, $35, $01, $88 ; luigi sprite 3

This works fine; when run, the program displays a Mario metasprite, with a Luigi metasprite underneath him.

My question is, how possible would it be to combine the create_mario and create_luigi subroutines into a single subroutine, using two variables (stored possibly in the stack/zero page/registers - wherever is best?) to define the sprite data and sprite RAM offsets?

Like in the following pseudocode:

Code: Select all

create_sprite:
	ldx	#$00
	
@loop:
	lda	spriteData+[SPRITE_DATA_OFFSET], x
	sta	$0200+[SPRITE_RAM_OFFSET], x
	inx
	cpx	#$10
	bne	@loop
	
	rts
Any thoughts? I reiterate that I am new to all of this, so apologies if this question is in any way idiotic! ;)

(I'm using ca65, if this affects the answer)
doppelganger
Posts: 183
Joined: Tue Apr 05, 2005 7:30 pm

Re: Displaying Metasprites

Post by doppelganger »

simseventy wrote:Hi guys,

I've recently started looking into programming for the NES. So far I've been playing around with sprites and nametables, just trying to get a feel for how it all works.

In one such experiment, I have the following two subroutines:

Code: Select all

create_mario:
	ldx	#$00
	
@loop:
	lda	spriteData, x
	sta	$0200, x
	inx
	cpx	#$10
	bne	@loop
	
	rts

;;;;;;;;;;;;;;;;;;;;;;

create_luigi:
	ldx	#$00
	
@loop:
	lda	spriteData+16, x
	sta	$0200+16, x
	inx
	cpx	#$10
	bne	@loop
	
	rts

This works fine; when run, the program displays a Mario metasprite, with a Luigi metasprite underneath him.

My question is, how possible would it be to combine the create_mario and create_luigi subroutines into a single subroutine, using two variables (stored possibly in the stack/zero page/registers - wherever is best?) to define the sprite data and sprite RAM offsets?
Easy. Just do something like this:

Code: Select all

ldx spritedataoffset
ldy spriteramoffset
jsr createsprite
<whatever code follows here>

createsprite:
txa
clc
adc #$10
sta temp
loop:
lda spritedata,x
sta spriteram,y
inx
iny
cpx temp
bne loop
rts
Be whatever the situation demands.
simseventy
Posts: 5
Joined: Sun Oct 27, 2013 6:17 am

Re: Displaying Metasprites

Post by simseventy »

doppelganger - thank you, works like a charm. :)
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Re: Displaying Metasprites

Post by thefox »

That will work as long as you have less than 256 bytes of metasprite data. When you have more, you're going to have to use some kind of indirect indexing, usually with LDA (foo),Y where foo is a pointer in the zeropage.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Displaying Metasprites

Post by tokumaru »

As usual, the answer to the question "how do I make this routine work with non-hardcoded data?" is indirect addressing / pointers. Look up the LDA ($XX), Y addressing mode thefox mentioned. With it you can have addresses stored in zero-page point to anywhere in the addressing space ($0000-$FFFF). So you con do this:

Code: Select all

	lda #<MarioMetasprite ;get the low byte of the metasprite
	sta MetaspritePointer+0 ;store it in the pointer
	lda #>MarioMetasprite ;get the low byte of the metasprite
	sta MetaspritePointer+1 ;store it in the pointer
	jsr DrawMetasprite ;call the drawing routine
The drawing routine will then use LDA (MetaspritePointer), Y to access the metasprite data, with Y starting at 0 and being incremented after every byte read. You'll definitely need pointers, because once you implement enemies and animations, 256 bytes will hardly be enough for all the metasprites you'll have.

And you'll probably need something more dynamic for setting the pointers than the example code above, since that function call is still hardcoded (even though the drawing function itself isn't). Ideally you'd implement object states (e.g. 0 = standing, 1 = walking, 2 = jumping, etc.), which are also needed for logic and physics, and an animation system to control which sprites are rendered for each character each frame. Animations can be pretty simple, consisting of a frame pointer and a frame counter for each object. The frame pointer indicates the current frame in the animation script, and the frame counter counts the frames until the next animation frame. The script can be just a list of metasprite pointers and frame durations, with some sort of flag indicating the end of the script.

The more dynamic things get, the more pointers you'll be using, this is normal.
simseventy
Posts: 5
Joined: Sun Oct 27, 2013 6:17 am

Re: Displaying Metasprites

Post by simseventy »

thefox, tokumaru - thank you for the invaluable additional advice. Indirect addressing was exactly the kind of thing I was looking for. Maybe I should read up on the fundamentals before I start asking the questions! :)
Post Reply