Jump to content
IGNORED

Re-use player sprites without duplication (DPC+)


wallaby

Recommended Posts

I'm currently having a problem where I have a single sprite, but I want to use it on two players.

 

I have to duplicate my sprite data for both players and use up more space in my graphics bank.

 

I can do:

 

player3:

{sprite data}

end

 

But if I want to use that exact same sprite, I have to duplicate it in ROM.

 

player4:

{exact same sprite data}

end

 

Instead of re-using the existing sprite data, I have to define it twice.

 

It becomes a problem when I want to have many different possible sprites for many players. Instead of having to duplicate the sprite 9 times in ROM, I'd rather have one sprite data, and re-use it for each player.

 

I tried using data to define the sprite, but there is no syntax for assigning data to a player. If there was, you could define data for your sprites and colors and swap them between players. Data is ROM, so in theory, you shouldn't need any trickery to get it to work. Maybe I can do this with an ASM macro?

 

If it's not possible to re-use existing data, I'll have to make it so only certain players can be certain sprites so there is no duplication in my graphics bank.

 

 

Link to comment
Share on other sites

Here is the code for setting the sprite data for player3. What I'm confused about is that it doesn't seem to matter what data I set, the assembly is always the same.

 

I think the first 4 lines are for setting the correct address to the sprite data. But then LDX loads something which is written to the sprite data. Then LDX loads another something that is written.

 

Then it writes how many lines the sprite uses.

 

So it must be loading two addresses (the start and end?) of the sprite data. The start and end never seems to change, so it must load the maximum and then just set how many lines it actually uses?

 

 

   7529  459f               a9 e6              lda    #<(playerpointers+4)
   7530  45a1               8d 50 10           sta    DF0LOW
   7531  45a4               a9 01              lda    #(>(playerpointers+4)) & $0F
   7532  45a6               8d 68 10           sta    DF0HI
   7533  45a9               a2 ae              LDX    #<playerL0514_3
   7534  45ab               8e 78 10           STX    DF0WRITE
   7535  45ae               a9 67              LDA    #((>playerL0514_3) & $0f) | (((>playerL0514_3) / 2) & $70)
   7536  45b0               8d 78 10           STA    DF0WRITE
   7537  45b3               a9 0e              LDA    #14
   7538  45b5               85 a8              STA    player3height

 

With that hypothesis, I made my own ASM. I put my own label and tried this, but it crashes.

 

 

playerL9
   .byte    %11111111
   .byte    %01111100
   .byte    %01101000
   .byte    %01101000
   .byte    %00010100
   .byte    %00010100
   .byte    %01111110
   .byte    %01111110
   .byte    %01111110
   .byte    %01111110
   .byte    %01111110
   .byte    %01111110
   .byte    %01111110
   .byte    %01111110
   lda    #<(playerpointers+4)
   sta    DF0LOW
   lda    #(>(playerpointers+4)) & $0F
   sta    DF0HI
   LDX    #<playerL9
   STX    DF0WRITE
   LDA    #((>playerL9) & $0f) | (((>playerL9) / 2) & $70)
   STA    DF0WRITE
   LDA    #14
   STA    player3height
Link to comment
Share on other sites

Oh, I got it!

 

Okay, first you define your sprite with data.

 

 

data mysprite
%01010101,
%10101010,
%10101010
end

 

Then you can reference the data label using the same assembly that is normally used.

 

 

   lda    #<(playerpointers+4)
   sta    DF0LOW
   lda    #(>(playerpointers+4)) & $0F
   sta    DF0HI
   LDX    #<mysprite
   STX    DF0WRITE
   LDA    #((>mysprite) & $0f) | (((>mysprite) / 2) & $70)
   STA    DF0WRITE
   LDA    #3
   STA    player3height

 

I think this allows you to use other banks for graphics data too. You wouldn't be limited by 4k using DPC+.

 

You could also save the sprites like normal, look in the ASM for the labels bB gave them, and use them interchangeably without having to redefine them. These would use the graphics bank.

 

I think that adds a lot of flexibility!

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

Do you know about the DPC+ kernel command to set a range of virtual players to one data?

 

In DK we have a lot of players that are the barrel.

 

Is this an answer to the question you asked?

So you can code:

barrels
 player4-7:
 %00111100
 %01111110
 %01111110
 %11111111
 %11111111
 %01111110
 %00111100
end

 playercolor4-7:
 $26
 $24
 $24
 $24
 $24
 $24
 $22
end
  • Like 2
Link to comment
Share on other sites

I think Wallaby is trying to make something where player0 and player1 can kind of 'swap' sprite data. When you assign the sprite to player0 you would then have to redraw the sprite again and call it player1, he would like to say player0 is this sprite OR player1 is this sprite, but I'm not making another!?

 

Now in the case of one sprite it is easily shared, but if you want to swap sprite identities using more than one sprite you would have to draw an identical 'other' sprite and waste data?

  • Like 1
Link to comment
Share on other sites

I think Wallaby is trying to make something where player0 and player1 can kind of 'swap' sprite data. When you assign the sprite to player0 you would then have to redraw the sprite again and call it player1, he would like to say player0 is this sprite OR player1 is this sprite, but I'm not making another!?

 

Now in the case of one sprite it is easily shared, but if you want to swap sprite identities using more than one sprite you would have to draw an identical 'other' sprite and waste data?

 

Excellent description Papa! :) I think the DPC+ kernel extension to map definitions to multiple players is pretty cool but imo being able to independently load the sprite definitions as you've described is very advantageous and what wallaby seems to be looking for.

 

Virtual World BASIC has this functionality with the loadsprite and loadspriteupsidedown commands. You can also access sprites like standard array variables to overwrite just specific rows.

 

wallaby great topic and design questions! Try vwBASIC for your next game if you need that kind of program architecture.

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...

Yes, that's what I was doing. I have a number of sprites. Each of them can be a monster character, but I didn't want player1 to always be the same monster. I wanted to be able to use one sprite in ROM for more than one player, but also change them. I ended up with a non-trivial way of doing this by calculating the addresses of the sprite data and storing them in the stack. When the game decided it wanted a particular monster, it would retrieve the LO and HI addresses from the stack and write the data. It works, but it's slow. I change monster sprites during screen transitions, so the slowness isn't a problem.

Link to comment
Share on other sites

Maybe you're making things too complicated Is this what you're trying to do?

I coded this and it works.

post-29575-0-49360300-1477415930_thumb.jpg

 

"dim" a variable, here I use "p0base"

code:

dim p0base=a

Set sprite(s) data.

(See image above)

My draw screen is one subroutine per bank if "drawscreen" is needed from more than one place inside the bank.

Then when you draw screen, set player0pointerlo and the height, and it will draw the piece of the sprite you need.

frack
 if diff{7} then player0pointerlo = 15+p0base
 player0height = 15 
frack3a
   DF0FRACINC=255: DF1FRACINC=255: DF2FRACINC=255: DF3FRACINC=255
  if level=2 || level=4 then DF4FRACINC=255

  drawscreen
  return thisbank

I gosub frack when I set the sprite choice, or frack3a when all is set and I just need "drawscreen".

 

  • Like 1
Link to comment
Share on other sites

That only changes the player0 sprite though.

 

Consider an 8x8 sprite that is a skeleton.

Now an 8x8 sprite that is a troll.

 

Now let's say you want that to player1 to be a skeleton.

 

Very straight forward.

 

But now you want player1 to be a troll. You need to change the sprite data for player 1. You could stack the sprites, like you did in your example and that works. But wait...

 

Now you need player2 to be a skeleton and player3 to be a skeleton.

 

You need to re-use your skeleton data for multiple DPC+ players without duplicating it.

 

The system I have set up defines the sprite once. Then it writes the data to whatever DPC+ player sprite that needs it. This allows me much more flexibility

Link to comment
Share on other sites

That only changes the player0 sprite though.

 

Consider an 8x8 sprite that is a skeleton.

Now an 8x8 sprite that is a troll.

 

Now let's say you want that to player1 to be a skeleton.

 

Very straight forward.

 

But now you want player1 to be a troll. You need to change the sprite data for player 1. You could stack the sprites, like you did in your example and that works. But wait...

 

Now you need player2 to be a skeleton and player3 to be a skeleton.

 

You need to re-use your skeleton data for multiple DPC+ players without duplicating it.

 

The system I have set up defines the sprite once. Then it writes the data to whatever DPC+ player sprite that needs it. This allows me much more flexibility

 

 

wallaby,

Could you post publicly or PM me privately with your method?

I might be able to get a lot more into DK Arcade if I did not have to redefine player numbers to different duplicated data.

Link to comment
Share on other sites

Sure, no problem. This community has helped me numerous times and it would be great to be able to contribute for once! But this isn't very elegant as can be complicated.

 

First, you need to define your graphics data as a data statement:

 

data my_sprite:

{sprite data here}

end

 

You'll also want the color information. You can use that as a data statement too.

 

data my_sprite_color:

{colors}

end

 

You can put this anywhere, but I put it in bank 7 (which is reserved for graphics data anyway.)

 

Now you need to store the lo and hi bytes of the sprite and colors.

 

I had a lot of trouble getting batari basic to work with it, so I resorted to ASM.

 

LDA #0
LDY #<my_sprite
JSR SetValue2
LDA #1
LDY #((>my_sprite) & $0f) | (((>my_sprite) / 2) & $70)
JSR SetValue2
LDA #128
LDY #<my_sprite_color
JSR SetValue2
LDA #129
LDY #((>my_sprite_color) & $0f) | (((>my_sprite_color) / 2) & $70)
JSR SetValue2

 

What I'm doing is getting the address bytes and storing them in an unused portion of the cartridge. The SetValue2 sub routine I got directly from this forum where we were asking for ways to use the stack as a variables (can't remember the title of the thread.) You'll need that routine. It's only a few lines and indispensable. I store the sprite starting at 0 and the colors starting at 128. You don't have to do it this way. I have no idea why I didn't just put all 4 bytes consecutively, but whatever.

 

At this point you have saved 4 bytes for your sprite. 2 for the graphics and 2 for the colors. To actually change our sprite, we need to get them back out and write them.

 

sprite_lo = GetValue2(0)

sprite_hi = GetValue2(1)

sprite_color_lo = GetValue2(128)

sprite_color_hi = GetValue2(129)

 

LDX sprite_lo
STX player0pointerlo
LDA sprite_hi
STA player0pointerhi
LDX sprite_color_lo
STX player0color
LDA sprite_color_hi
STA player0color+1

 

And that will set our player0 sprite to whatever we defined as our data.

 

To change the sprite to something else, all you need to do is get the 4 bytes from whereever you put them, and write them again. Once you get one sprite working it's trivial to use others. What it isn't is fast.

Link to comment
Share on other sites

Sure, no problem. This community has helped me numerous times and it would be great to be able to contribute for once! But this isn't very elegant as can be complicated.

 

First, you need to define your graphics data as a data statement:

 

data my_sprite:

{sprite data here}

end

 

You'll also want the color information. You can use that as a data statement too.

 

data my_sprite_color:

{colors}

end

 

You can put this anywhere, but I put it in bank 7 (which is reserved for graphics data anyway.)

.

.

.

 

To change the sprite to something else, all you need to do is get the 4 bytes from whereever you put them, and write them again. Once you get one sprite working it's trivial to use others. What it isn't is fast.

 

 

when I tryed to put stuff in bank 7 DASM complained

did you do anything special to get it to work?

 

why not have the sprite addresses in ROM?

Link to comment
Share on other sites

Interesting. Bank 7 works okay for me. I wonder if I have a newer or older version of DASM? I didn't expect it to work in Bank 7, but when I tried, it runs fine.

 

As for ROM locations - it would be fine if you could calculate the address before it's compiled. I don't know how to do that. Plus, I think the address would change anytime you added anything and you'd have to re-do it. I tried experimenting with setting the address in a constant but it sometimes didn't work.

Link to comment
Share on other sites

 

    LDA #0
    LDY #<my_sprite
    JSR SetValue2
    LDA #1
    LDY #((>my_sprite) & $0f) | (((>my_sprite) / 2) & $70)
    JSR SetValue2
    LDA #128
    LDY #<my_sprite_color
    JSR SetValue2
    LDA #129
    LDY #((>my_sprite_color) & $0f) | (((>my_sprite_color) / 2) & $70)
    JSR SetValue2

 

This set of ASM functions are costing me a fair amount of space. Is there any way to pre-calculate the addresses in constants so I can set them in bB without having to calculate them on the Atari?

Link to comment
Share on other sites

This set of ASM functions are costing me a fair amount of space. Is there any way to pre-calculate the addresses in constants so I can set them in bB without having to calculate them on the Atari?

I count 28 bytes of ROM in total.

 

All of the operations in brackets are being calculated during compile-time and turned into constants. The 6502 only sees a single value in their place.

Link to comment
Share on other sites

 

 

All of the operations in brackets are being calculated during compile-time and turned into constants. The 6502 only sees a single value in their place.

 

That's really clever! Any other way to store memory addresses so I can just place the high and low bits without having to look them up first? The way I do it now, works, but it's slow and cumbersome. I load them up here when the game starts. When I need a sprite or color data, I have to look them up again, retrieve the values, then store them in the right places. If I could cut out the looking up and storing and just use a constant value I'd save a lot of messing around.

Link to comment
Share on other sites

Yeah, for sprite and color tables there isn't an easy way to get to those location pointers from basic.

 

What you can do instead is copy the generated assembly from the player0: command into your basic, making sure any labels will remain unique. (Ie. Ones that won't possibly match other bB auto-generated labels)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...