Sprite animation (state)

ZX80, ZX 81, ZX Spectrum, TS2068 and other clones
Post Reply
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Sprite animation (state)

Post by amateus »

Hi,

I've been messing around with sprite animations and I've tried both usual ways:
  • updating the sp1_ss frame with the next frame using a memory offset
  • initializing the sprite with a 0 value and specifying the memory pointer in MoveSprPix
Both are ok for 8x8 sprite, but when it comes to bigger sprites I'm facing a problem which should be simple but it's driving me mad.

Consider the following code for a 16x16 sprite (so, 2 columns):

Initialize sprite with a 0 pointer

Code: Select all

hero.s = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 10);
sp1_AddColSpr(hero.s, SP1_DRAW_MASK2,    SP1_TYPE_2BYTE, 0, 10);
sp1_AddColSpr(hero.s, SP1_DRAW_MASK2RB,  SP1_TYPE_2BYTE, 0, 10);
Position the sprite, specifying the memory pointer of the graphic

Code: Select all

sp1_MoveSprPix(hero.s, &full_screen, state[hero.state].graphic_col1, hero.x, hero.y);
But.... this is a 2 column sprite. The question is: where do I specify the 2nd column?

Can someone enlighten me?

Thanks,
António
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Sprite animation (state)

Post by amateus »

And I think I found out. On adding the second columns I need to add the frame offset from the first column.

In my case it has to be:

sp1_AddColSpr(hero.s, SP1_DRAW_MASK2, SP1_TYPE_2BYTE, 48, 10);
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

Re: Sprite animation (state)

Post by Timmy »

I've just demonstrated how to do different sized sp1 sprites earlier this month in this thread: viewtopic.php?f=2&t=11448 (note that I'm not sure there if that is the correct way to store sprite data. I forgot how, I guess :P ).

There's also a 10-year old thread here that explained the sprites a bit more in wos: https://worldofspectrum.org/forums/disc ... ent_432492
amateus
Member
Posts: 46
Joined: Fri Nov 15, 2019 9:13 am

Re: Sprite animation (state)

Post by amateus »

ah didn't saw that. nice, will check, thanks
derekfountain
Member
Posts: 121
Joined: Mon Mar 26, 2018 1:49 pm

Re: Sprite animation (state)

Post by derekfountain »

amateus wrote: Sun Jan 31, 2021 4:26 pm But.... this is a 2 column sprite. The question is: where do I specify the 2nd column?
The 4th argument to the first call to sp1_AddColSpr() needs to contain an offset from the data for the first column to the data to the second column. It's described here:

https://github.com/z88dk/z88dk/blob/mas ... Sprites.md

This allows SP1 to know how to get from one column's data to the next column's data. The example code in that article is this:

Code: Select all

bubble_sprite = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0);
sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2,    SP1_TYPE_2BYTE, bubble_col2-bubble_col1, 0);
sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2RB,  SP1_TYPE_2BYTE, 0, 0);
It's using the compiler to calculate the difference, which for the example in the article is actually 48 bytes.
Timmy
Well known member
Posts: 392
Joined: Sat Mar 10, 2012 4:18 pm

Re: Sprite animation (state)

Post by Timmy »

derekfountain wrote: Sun Jan 31, 2021 5:38 pm

Code: Select all

bubble_sprite = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0);
sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2,    SP1_TYPE_2BYTE, bubble_col2-bubble_col1, 0);
sp1_AddColSpr(bubble_sprite, SP1_DRAW_MASK2RB,  SP1_TYPE_2BYTE, 0, 0);
It's using the compiler to calculate the difference, which for the example in the article is actually 48 bytes.
I was just trying out this bit of code in a short example. Surprisingly, changing "48" into "bubble_col2-bubble_col1" made my example code 8 bytes larger.

My suspicion is that this is being evaluated in runtime, and therefore the compiler doesn't really calculate the difference. But perhaps I'm doing it wrong.

*) Note: Your results may vary.
User avatar
dom
Well known member
Posts: 2076
Joined: Sun Jul 15, 2007 10:01 pm

Re: Sprite animation (state)

Post by dom »

Timmy wrote: Mon Feb 01, 2021 12:08 pmI was just trying out this bit of code in a short example. Surprisingly, changing "48" into "bubble_col2-bubble_col1" made my example code 8 bytes larger.

My suspicion is that this is being evaluated in runtime, and therefore the compiler doesn't really calculate the difference. But perhaps I'm doing it wrong.
Yeah, this will be being evaluated at runtime. It's an interesting optimisation to try out though, consider it on my todo list.
derekfountain
Member
Posts: 121
Joined: Mon Mar 26, 2018 1:49 pm

Re: Sprite animation (state)

Post by derekfountain »

You're absolutely right. The generated code is:

Code: Select all

539   0037  3E 00               ld      a, +((_bubble_col2) & 0xFF)
540   0039  D6 00               sub     a, +((_bubble_col1) & 0xFF)
541   003B  5F                  ld      e, a
542   003C  3E 00               ld      a, +((_bubble_col2) / 256)
543   003E  DE 00               sbc     a, +((_bubble_col1) / 256)
544   0040  57                  ld      d, a
So the compiler isn't calculating the difference, it's generating code to calculate it at runtime.
User avatar
jorgegv
Well known member
Posts: 287
Joined: Wed Nov 18, 2020 5:08 pm

Re: Sprite animation (state)

Post by jorgegv »

In RAGE1, the tool that converts graphic sprite data to C data arrays (datagen.pl), also generates the sprite initialization function (which is a trivial function with initialization code for all defined sprites).

Since all these numbers are known at code generation time, the generated code only contains constants, and so it avoids any calculation at runtime.

In fact, RAGE1 intends to automatically generate as much static data as possible, even with interrelated pointers, so that the amount of code for runtime calculations/initializations is minimized. I'd love to have some better documentation to even statically generate the full SP1 sprite structs, instead of having to generate code to call sp1_AddSpr, sp1_AddCol, etc.

If you build the RAGE1 demo game, you can check file generated/game_data.c to see what I'm talking about:

Code: Select all

void init_screen_sprite_tables(void) {
        struct sp1_ss *s;       // temporary storage

        // Screen 'Screen01' - Sprite initialization
        map[0].sprite_data.num_sprites = 3;

        // Sprite 'Ghost01'
        map[0].sprite_data.sprites[0].sprite = s = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2, 0, 48, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2RB, 0, 0, 0);
        SET_SPRITE_FLAG( map[0].sprite_data.sprites[0], F_SPRITE_ACTIVE );
        // End of Sprite 'Ghost01'

        // Sprite 'GhostPNG'
        map[0].sprite_data.sprites[1].sprite = s = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2, 0, 48, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2RB, 0, 0, 0);
        SET_SPRITE_FLAG( map[0].sprite_data.sprites[1], F_SPRITE_ACTIVE );
        // End of Sprite 'GhostPNG'

        // Sprite 'GhostPNG'
        map[0].sprite_data.sprites[2].sprite = s = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2, 0, 48, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2RB, 0, 0, 0);
        SET_SPRITE_FLAG( map[0].sprite_data.sprites[2], F_SPRITE_ACTIVE );
        // End of Sprite 'GhostPNG'

        // Screen 'Screen01' - End of Sprite initialization

        // Screen 'Screen02' - Sprite initialization
        map[1].sprite_data.num_sprites = 1;

        // Sprite 'GhostPNG'
        map[1].sprite_data.sprites[0].sprite = s = sp1_CreateSpr(SP1_DRAW_MASK2LB, SP1_TYPE_2BYTE, 3, 0, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2, 0, 48, 0 );
        sp1_AddColSpr(s, SP1_DRAW_MASK2RB, 0, 0, 0);
        SET_SPRITE_FLAG( map[1].sprite_data.sprites[0], F_SPRITE_ACTIVE );
        // End of Sprite 'GhostPNG'

        // Screen 'Screen02' - End of Sprite initialization


}

Post Reply