Jump to content
IGNORED

Help with RAM sprites


jrok

Recommended Posts

I'm working on a project right now that uses the Superchip to write the shape data for both player sprites. It's working fine, but I seem to recall a nifty sample which Michael (SeaGTGruff) wrote in which part of the data was stored in ROM and part in RAM. I have combed the forum until my eyes hurt, but I can't seem to find it.

 

Michael if you read this, do you recall the sample program I am talking about? I couldn't find it by searching keywords nor by searching page by page.

 

Thanks in advance,

Jarod.

Link to comment
Share on other sites

I'm working on a project right now that uses the Superchip to write the shape data for both player sprites. It's working fine, but I seem to recall a nifty sample which Michael (SeaGTGruff) wrote in which part of the data was stored in ROM and part in RAM. I have combed the forum until my eyes hurt, but I can't seem to find it.

 

Michael if you read this, do you recall the sample program I am talking about? I couldn't find it by searching keywords nor by searching page by page.

 

Thanks in advance,

Jarod.

I think the example I did was in the thread called "Superchip Bankswitching in bB," which was before Fred (batari) officially added Superchip support to bB. I haven't gone back to look at the code, and I seem to recall doing another example before that which used the page zero RIOT RAM, but the concept is pretty simple...

 

When you do a player0: or player1: statement in bB, the bB compiler stores your player shape data in ROM using .byte statements, giving it a label-- usually something like playerL01_0, though the number after the L will vary depending on the line number where the player0: or player1: statement appears. The shape data is stored after the code for your program statements. Then the bB compiler sets three bB variables-- player0pointerlo and player0pointerhi, which are set to the lo and hi bytes of the label for the shape data (i.e., the address where the data is stored in ROM), and player0height, which is set to 1 less than the number of lines of data. For example, if your player is 10 lines high, then player0height will be set to 9, since the lines are numbered starting with line 0, so 0 through 9 is equal to 10 lines.

 

This means you can easily store your player data in ROM by yourself, such as defining 64 bytes of data for a table of 8 consecutive player shapes, each 8 lines tall, stacked one after the other, and then all you need to do is manually set the lo and hi pointers to the address of the particular shape you want to draw, and set the height variable to the appropriate value (in this case, 7 if you want the player to be 8 lines tall).

 

To make a RAM player, you just set aside the appropriate number of consecutive bytes in RAM, then set the lo and hi player pointers to the address of the first byte, and set the height variable. Once you've done that, you don't use the player0: (or player1:) statement, because it will mess up your pointers. Instead, just copy the shape you want into the RAM variables, one byte at a time.

 

If you're using zero-page RIOT RAM, the hi byte will be 0, and the lo byte will be the address of the first RAM variable you're using. For example, say you've decided to use variables a through h for 8 bytes of data for player0. Then you could do something like the following:

 

  const p0_lo = <a
  player0pointerlo = p0_lo
  player0pointerhi = 0
  player0height = 7
  player0x = 76
  player0y = 44
loop
  a = rand
  b = rand
  c = rand
  d = rand
  e = rand
  f = rand
  g = rand
  h = rand
  COLUP0 = rand
  drawscreen
  goto loop

This example just sets the player0 shape to random bytes and a random color, but you could just as easily copy a shape from ROM into the RAM variables.

 

If you're using Superchip RAM for the player, it's pretty much the same, except the hi byte will be $F0, or the page number where the Superchip RAM is located. Also, you have to remember that you must write to one address and read from another address. That means you would set the pointers to the read address, and use the write addresses to update the data, as in the following example:

 

  set romsize 8kSC
  const p0_lo = <r000
  const p0_hi = >r000
  player0pointerlo = p0_lo
  player0pointerhi = p0_hi
  player0height = 7
  player0x = 76
  player0y = 44
loop
  w000 = rand
  w001 = rand
  w002 = rand
  w003 = rand
  w004 = rand
  w005 = rand
  w006 = rand
  w007 = rand
  COLUP0 = rand
  drawscreen
  goto loop

99% of the time, it's best to just use ROM player shapes, because drawing the player from RAM offers no real benefit. But there might be occasions when it's useful to draw the player from RAM, such as part of the player's shape will always be the same, and only the remaining part will ever vary, and you don't want to duplicate the part that will always be the same in your ROM data. Or maybe you want to do something unusual like fill the player's shape with random values, or scroll the shape, etc.

 

Here's an example of scrolling a shape:

 

  set romsize 8kSC
  const p0_lo = <r000
  const p0_hi = >r000
  player0pointerlo = p0_lo
  player0pointerhi = p0_hi
  player0height = 7
  player0x = 76
  player0y = 44
  w000 = p0[0]
  w001 = p0[1]
  w002 = p0[2]
  w003 = p0[3]
  w004 = p0[4]
  w005 = p0[5]
  w006 = p0[6]
  w007 = p0[7]
loop
  temp3 = r000
  temp4 = r001 / 128
  w000 = r001 * 2 + temp4
  temp4 = r002 / 128
  w001 = r002 * 2 + temp4
  temp4 = r003 / 128
  w002 = r003 * 2 + temp4
  temp4 = r004 / 128
  w003 = r004 * 2 + temp4
  temp4 = r005 / 128
  w004 = r005 * 2 + temp4
  temp4 = r006 / 128
  w005 = r006 * 2 + temp4
  temp4 = r007 / 128
  w006 = r007 * 2 + temp4
  temp4 = temp3 / 128
  w007 = temp3 * 2 + temp4
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  goto loop
  data p0
  000000
  011000
  100100
  %01000010
  %01000010
  100100
  011000
  000000
end

(The four drawscreen statements are just to slow it down.)

 

And here's an example of changing (scrolling) part of the shape and leaving the rest of the shape alone:

 

  include div_mul.asm
  set romsize 8kSC
  const p0_lo = <r000
  const p0_hi = >r000
  player0pointerlo = p0_lo
  player0pointerhi = p0_hi
  player0height = 8
  player0x = 76
  player0y = 44
  w000 = p0[0]
  w001 = p0[1]
  w002 = p0[2]
  w003 = p0[3]
  w004 = p0[4]
  w005 = p0[5]
  w006 = p0[6]
  w007 = p0[7]
  w008 = p0[8]
loop
  temp4 = r000 * 128
  w000 = r000 / 2 + temp4
  temp4 = r001 * 128
  w001 = r001 / 2 + temp4
  temp4 = r002 * 128
  w002 = r002 / 2 + temp4
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  COLUP0 = $4C
  drawscreen
  goto loop
  data p0
  %11001100
  %01000100
  %01000100
  %11111111
  %01111110
  111100
  011000
  111100
  111100
end

It's not a great animation, since the toes get left behind, but it's just an example to show how you can change just part of the shape if you want.

 

Michael

Link to comment
Share on other sites

Thanks Michael. Yes, this all makes much more sense than what I was (mis)remembering. One other question I had was, is there a way to go about defining a sprite shape in ROM and then accessing it in RAM.

 

For example, suppose I wanted to draw some trees using the Superchip.

 

I start with one tree:

 


dim w_GRP0 = w016
dim r_GRP0 = r016

RAMterrain
  asm
  LDA #<r_GRP0
  STA player0pointerlo
  LDA #>r_GRP0
  STA player0pointerhi
end

w_GRP0[14] = %00000101
w_GRP0[13] = %00011010
w_GRP0[12] = %01001011
w_GRP0[11] = %01110111
w_GRP0[10] = %01011010
w_GRP0[9] =  %00111111
w_GRP0[8] =  %11011011
w_GRP0[7] =  %11100111
w_GRP0[6] =  %01011010
w_GRP0[5] =  %11111101
w_GRP0[4] =  %11011011
w_GRP0[3] =  %00000001
w_GRP0[2] =  %00000001
w_GRP0[1] =  %00000001
w_GRP0[0] =  %00000011

 

And then I add two more by reading the data written to the first tree, forming a vertical line of three trees:

 

 w_GRP0[15] =  r_GRP0[0]
w_GRP0[16] =  r_GRP0[1]
w_GRP0[17] =  r_GRP0[2]
w_GRP0[18] =  r_GRP0[3]
w_GRP0[19] =  r_GRP0[4]
w_GRP0[20] =  r_GRP0[5]
w_GRP0[21] =  r_GRP0[6]
w_GRP0[22] =  r_GRP0[7]
w_GRP0[23] =  r_GRP0[8]
w_GRP0[24] =  r_GRP0[9]
w_GRP0[25] =  r_GRP0[10]
w_GRP0[26] =  r_GRP0[11]
w_GRP0[27] =  r_GRP0[12]
w_GRP0[28] =  r_GRP0[13]
w_GRP0[29] =  r_GRP0[14]
w_GRP0[30] =  r_GRP0[0]
w_GRP0[31] =  r_GRP0[1]
w_GRP0[32] =  r_GRP0[2]
w_GRP0[33] =  r_GRP0[3]
w_GRP0[34] =  r_GRP0[4]
w_GRP0[35] =  r_GRP0[5]
w_GRP0[36] =  r_GRP0[6]
w_GRP0[37] =  r_GRP0[7]
w_GRP0[38] =  r_GRP0[8]
w_GRP0[39] =  r_GRP0[9]
w_GRP0[40] =  r_GRP0[10]
w_GRP0[41] =  r_GRP0[11]
w_GRP0[42] =  r_GRP0[12]
w_GRP0[43] =  r_GRP0[13]
w_GRP0[44] =  r_GRP0[14]

player0height = 44

 

Would there be a way to define the first tree shape in ROM, while writing its duplicates to RAM?

 

Thanks again for all the kind help.

 

Jarod.

 

EDT: By "writing its duplicates to RAM," I guess what i really mean is targeting the individual lines of the sprite stored in ROM.

Edited by jrok
Link to comment
Share on other sites

Thanks Michael. Yes, this all makes much more sense than what I was (mis)remembering. One other question I had was, is there a way to go about defining a sprite shape in ROM and then accessing it in RAM.

 

For example, suppose I wanted to draw some trees using the Superchip.

 

I start with one tree:

 

[...]

 

And then I add two more by reading the data written to the first tree, forming a vertical line of three trees:

 

[...]

 

Would there be a way to define the first tree shape in ROM, while writing its duplicates to RAM?

What you should do is store the shape for 1 tree in ROM, define the RAM player to be tall enough for 3 trees, and copy the ROM into RAM 3 times. :) The easiest way would probably be as follows:

 

  set romsize 8kSC

  const P0_lo = <r000
  const P0_hi = >r000

  player0pointerlo = P0_lo
  player0pointerhi = P0_hi
  player0height = 50

  player0x = 76
  player0y = 70

  temp1 = P0[0]  : w000 = temp1 : w017 = temp1 : w034 = temp1
  temp1 = P0[1]  : w001 = temp1 : w018 = temp1 : w035 = temp1
  temp1 = P0[2]  : w002 = temp1 : w019 = temp1 : w036 = temp1
  temp1 = P0[3]  : w003 = temp1 : w020 = temp1 : w037 = temp1
  temp1 = P0[4]  : w004 = temp1 : w021 = temp1 : w038 = temp1
  temp1 = P0[5]  : w005 = temp1 : w022 = temp1 : w039 = temp1
  temp1 = P0[6]  : w006 = temp1 : w023 = temp1 : w040 = temp1
  temp1 = P0[7]  : w007 = temp1 : w024 = temp1 : w041 = temp1
  temp1 = P0[8]  : w008 = temp1 : w025 = temp1 : w042 = temp1
  temp1 = P0[9]  : w009 = temp1 : w026 = temp1 : w043 = temp1
  temp1 = P0[10] : w010 = temp1 : w027 = temp1 : w044 = temp1
  temp1 = P0[11] : w011 = temp1 : w028 = temp1 : w045 = temp1
  temp1 = P0[12] : w012 = temp1 : w029 = temp1 : w046 = temp1
  temp1 = P0[13] : w013 = temp1 : w030 = temp1 : w047 = temp1
  temp1 = P0[14] : w014 = temp1 : w031 = temp1 : w048 = temp1
  w015 = 0 : w032 = 0 : w049 = 0
  w016 = 0 : w033 = 0 : w050 = 0

loop

  COLUP0 = $C6

  drawscreen

  goto loop

  data P0
  %00000011
  %00000001
  %00000001
  %00000001
  %11011011
  %11111101
  %01011010
  %11100111
  %11011011
  %00111111
  %01011010
  %01110111
  %01001011
  %00011010
  %00000101
end

I don't see any reason to dim the write addresses, because (if I'm not mistaken) you can't say "this[1] = that[1]" in bB. You can reference an array on the right side of the equals, but not on the left side. And if you want to set multiple variables to the same value, it saves some bytes (and cycles) if you do them on the same line, one afer the other (e.g., "a = 1 : b = 1 : c = 1"). I set temp1 first, then set the write variables to temp1, because I wasn't sure if "a = this[1] : b = this[1] : c = this[1]" would optimize as desired when it's compiled.

 

Also, note my use of const to get the lo and hi bytes of the read address. I was able to code everything in bB without any inline assembly! :)

 

Michael

 

Edit: Fixed the binary values. (The forum software was hungry for %00. :ponder:)

post-7456-127207404511_thumb.png

Edited by SeaGtGruff
Link to comment
Share on other sites

Thanks, Michael! This is exactly what I trying to figure out.

 

What you should do is store the shape for 1 tree in ROM, define the RAM player to be tall enough for 3 trees, and copy the ROM into RAM 3 times. :) The easiest way would probably be as follows:

 

  set romsize 8kSC

  const P0_lo = <r000
  const P0_hi = >r000

  player0pointerlo = P0_lo
  player0pointerhi = P0_hi
  player0height = 50

  player0x = 76
  player0y = 70

  temp1 = P0[0]  : w000 = temp1 : w017 = temp1 : w034 = temp1
  temp1 = P0[1]  : w001 = temp1 : w018 = temp1 : w035 = temp1
  temp1 = P0[2]  : w002 = temp1 : w019 = temp1 : w036 = temp1
  temp1 = P0[3]  : w003 = temp1 : w020 = temp1 : w037 = temp1
  temp1 = P0[4]  : w004 = temp1 : w021 = temp1 : w038 = temp1
  temp1 = P0[5]  : w005 = temp1 : w022 = temp1 : w039 = temp1
  temp1 = P0[6]  : w006 = temp1 : w023 = temp1 : w040 = temp1
  temp1 = P0[7]  : w007 = temp1 : w024 = temp1 : w041 = temp1
  temp1 = P0[8]  : w008 = temp1 : w025 = temp1 : w042 = temp1
  temp1 = P0[9]  : w009 = temp1 : w026 = temp1 : w043 = temp1
  temp1 = P0[10] : w010 = temp1 : w027 = temp1 : w044 = temp1
  temp1 = P0[11] : w011 = temp1 : w028 = temp1 : w045 = temp1
  temp1 = P0[12] : w012 = temp1 : w029 = temp1 : w046 = temp1
  temp1 = P0[13] : w013 = temp1 : w030 = temp1 : w047 = temp1
  temp1 = P0[14] : w014 = temp1 : w031 = temp1 : w048 = temp1
  w015 = 0 : w032 = 0 : w049 = 0
  w016 = 0 : w033 = 0 : w050 = 0

loop

  COLUP0 = $C6

  drawscreen

  goto loop

  data P0
  000011
  000001
  000001
  000001
  %11011011
  %11111101
  %01011010
  %11100111
  %11011011
  111111
  %01011010
  %01110111
  %01001011
  011010
  000101
end

I don't see any reason to dim the write addresses, because (if I'm not mistaken) you can't say "this[1] = that[1]" in bB. You can reference an array on the right side of the equals, but not on the left side. And if you want to set multiple variables to the same value, it saves some bytes (and cycles) if you do them on the same line, one afer the other (e.g., "a = 1 : b = 1 : c = 1"). I set temp1 first, then set the write variables to temp1, because I wasn't sure if "a = this[1] : b = this[1] : c = this[1]" would optimize as desired when it's compiled.

 

Also, note my use of const to get the lo and hi bytes of the read address. I was able to code everything in bB without any inline assembly! :)

 

Michael

 

Edit: Fixed the binary values. (The forum software was hungry for %00. :ponder:)

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...