Page 29 of 109

Posted: Wed Nov 09, 2011 1:49 pm
by unregistered
unregistered wrote:Read my psuedocode:

Code: Select all

1.) read list of metatiles
2.) read "start" screen
3.) display '    '
#1 isnt required because it is already listed as .db statements so all I have to do is include it.
#2 isnt required for the same reason.. i think.

So my question is about line #3. I'm worrying about changing the label names inside each list of metatiles. Is there a way to include each file without making label-name changes?
...Um that was about line #1... sorry (could you answer it though? :) )
3gengames wrote:What are you trying to do? Is this for selecting on the main menu "Start" or then "Continue" or something, or trying to add it to the screen like "Level one!" then a little later "Go!" or something on the screen?
No, sorry, my sister named each screen that you start on "...start." I was refering to that. Reading the "start" screen's metatile 240 byte representation...

Posted: Wed Nov 09, 2011 2:28 pm
by 3gengames
Just text on the screen I'd maybe find a way to do that dynamically. I mean, mostly text isn't used in a game environment per say. I hope that may help some. Unless you need text on the screen in your game and adding it dynamically would be too hard/too CPU intensive.

Posted: Wed Nov 09, 2011 3:37 pm
by unregistered
3gengames wrote:Just text on the screen I'd maybe find a way to do that dynamically. I mean, mostly text isn't used in a game environment per say. I hope that may help some. Unless you need text on the screen in your game and adding it dynamically would be too hard/too CPU intensive.
How would you add text dynamically? :?

Posted: Wed Nov 09, 2011 4:03 pm
by 3gengames
Via a subroutine that adds it on to the screen when needed or have it put it on the background when you hit a certain part of the map, rewriting the meta tiles being written on the screen. Having metatiles just for some text messages might work good enough, but anything bigger and it'd create way too many.

Posted: Wed Nov 09, 2011 4:55 pm
by Kasumi
Forgive me if I'm dense, but I'm still confused with what you're trying to do.

You have completed the following steps, correct?

1. Made a series of .db statements for your metatiles.
2. Made a .db statement with the label "start:" for each (starting) screen? (I am led to believe this from the following quote)
No, sorry, my sister named each screen that you start on "...start." I was refering to that. Reading the "start" screen's metatile 240 byte representation...
So if this is your only question:
Is there a way to include each file without making label-name changes?
No. You can't have two labels with the same name. That said, it's not that hard to fix with a find replace (usually ctrl+h) in each file. (Assuming I understand your problem correctly)

Edit: And btw, if I were you I would get a hex editor and make binary files for large collections of data.

Then you just do something like

Code: Select all

label:
     .incbin "metatileset00.bin"
instead of

Code: Select all

label:
     .db $00, $00, $01;etc, etc, etc
So you are now trying to display the start screen? Or you already have the start screen displayed want to display text over the start screen? (which is the understanding of the problem I believe 3gengames got)

Please explain fully, since "Display ' ' " was very ambiguous. Assume I have no knowledge of what you are trying to accomplish OR what you have already done.

Edit2: Ooh, and can you post your metatile definition file? Something tells me you might be doing something in a much harder way than you need to.

Posted: Wed Nov 09, 2011 6:37 pm
by unregistered
Kasumi, please forgive me... I'm so sorry it is so confusing. :(
Kasumi wrote:You have completed the following steps, correct?

1. Made a series of .db statements for your metatiles.
yes
Kasumi wrote:2. Made a .db statement with the label "start:" for each (starting) screen?
No, my sister has labeled each level's starting screen with "start" at the end. I was just referring to that screen... for any one level. :)
Kasumi wrote:So if this is your only question:
Is there a way to include each file without making label-name changes?
No. You can't have two labels with the same name. That said, it's not that hard to fix with a find replace (usually ctrl+h) in each file... ...Edit: And btw, if I were you I would get a hex editor and make binary files for large collections of data.
Ah, that sounds interesting :D, thank you for mentioning it and thank you for answering my question! :)
Kasumi wrote:Please explain fully, since "Display ' ' " was very ambiguous. Assume I have no knowledge of what you are trying to accomplish OR what you have already done.
"Display ' '" was easier to type for me than 'Display "start" screen.'... right now I'm about to try displaying the 240 byte "start" screen.
Kasumi wrote:Edit2: Ooh, and can you post your metatile definition file? Something tells me you might be doing something in a much harder way than you need to.
That is very kind of you :), but my sister said wait. And she created our metatile definition file... so it's her decision.

edit: 3gengames, thanks for responding! :D Sorry, I was planning on including this message to you in my post... but then I got very distracted and forgot. Now it's time to sleep. Good night. :)

Posted: Wed Nov 09, 2011 7:25 pm
by Kasumi
Ah, I get it. So like:

Code: Select all

start:
     .db ;bytes for screen 0
start:
     .db ;bytes for screen 1
Yeah, can't be done that way. How would the assembler know what label lda start refers to when there are two "start"s? Personally, I name them screenX_Y. X is the set number, Y is the actual screen number in hex.

Displaying a screen is where it starts to get a little tough.

To update tiles in a nametable, you use $2006, and $2007. Easy mode involves no scrolling (for now).

First disable rendering and set the PPU to increment by one by writing the relevant bits to $2000.

Then write the address of a name table to $2006 in two writes.

Code: Select all

;No indentation for the instructions, but you'll get the point.
lda #$20
sta $2006;Sets the high byte of the address $2007 will write to.
lda #$00
sta $2006;Sets the low byte of the address $2007 will write to.

sta $2007;Writes #$00 to PPU address $2000. (which is the first tile of the first name table)
lda #$FF
sta $2007;Writes #$FF to PPU address $2001. (which is the tile to the right of the first tile)
You'll see that every write increases the destination address by one. This is so you don't have to keep setting $2006 which is slow. It's also possible to make the destination address increase by 32 each write. This is so you can write a column of tiles. (256/8 = 32 tiles across. So each write will give you the address of the tile below the last one written)

In any case:

You know that your metatiles contain a reference to 4 actual tiles.

After setting the name table address with $2006:

1. You load the first metatile in your screen's index number.
2. You load the top left tile of that metatile using the index.
3. You write this to $2007.
4. You load the top right tile of that metatile using the index.
5. You write this to $2007.
6. load the second metatile in your screen's index number.
(Why? Because the other two tiles in the first metatile refer to the row of tiles BELOW the one you're dealing with)
7. Repeat steps 2-5.
8. Load the third tile... etc etc etc until the entire of the first row is written
9. Load the first metatile in your screen's index number AGAIN.
10. Load the BOTTOM left tile of that metatile using the index.
11. You write this to $2007.

And from there you should be able to figure out the rest for tiles, but probably not attributes. Reenable rendering when you're done writing to $2007, and you'll see the result.

There are ways to load each metatile in the screen only once, but make some code that is easy to do and works before you get clever.

For attributes, you do kind of the same thing. Write the address of the attribute tile you want to update to $2006, then write the actual attribute to $2007. Because of your metatile format, this might actually be really easy for you to figure out. (It's hard as hell to do in my format :lol: ... I digress)

That's... about all I will say. Good luck! Try it, and post some code if you get stuck! I've never asked, will your game scroll? If yes, hopefully only in one direction at a time? If no.. :?

Posted: Thu Nov 10, 2011 5:07 am
by tokumaru
For working with different sets of data (i.e. the different screens of different levels) you have to use pointers, I already told you that. That example was for different sets of collision tables, but the principle is exactly the same for everything else.

A pointer is an address you can modify dynamically, so if you use pointers to access the data you can have the same code work with different sets of data just by modifying the pointer dynamically.

Posted: Fri Nov 11, 2011 1:48 pm
by unregistered
tokumaru wrote:For working with different sets of data (i.e. the different screens of different levels) you have to use pointers, I already told you that. That example was for different sets of collision tables, but the principle is exactly the same for everything else.

A pointer is an address you can modify dynamically, so if you use pointers to access the data you can have the same code work with different sets of data just by modifying the pointer dynamically.
Thank you for telling me again tokumaru! :D It suddenly makes sense after I spent time understanding this part of 6502.txt:

Code: Select all

  10) Post-indexed indirect-
  In this mode the contents of a zero-page address (and the following byte)
  give the indirect addressm which is added to the contents of the Y-register
  to yield the actual address of the operand. Again, inassembly language,
  the instruction is indicated by parenthesis.
  eg.  LDA ($4C), Y
  Note that the parenthesis are only around the 2nd byte of the instruction
  since it is the part that does the indirection.
  Assume the following -        byte       value
                                $004C      $00
                                $004D      $21
                                Y-reg.     $05
                                $2105      $6D
  Then the instruction above executes by:
  (i)   getting the address in bytes $4C, $4D = $2100
  (ii)  adding the contents of the Y-register = $2105
  (111) loading the contents of the byte $2105 - i.e. $6D into the
        accumulator.
  Note: only the Y-register is used in this mode.
and then I reread your post you linked to many times. Awesome to understand and know; now I need to use it! :D
added in edit

Posted: Sat Nov 12, 2011 11:50 pm
by unregistered
Kasumi wrote:Displaying a screen is where it starts to get a little tough.

To update tiles in a nametable, you use $2006, and $2007. Easy mode involves no scrolling (for now).

First disable rendering and set the PPU to increment by one by writing the relevant bits to $2000.

Then write the address of a name table to $2006 in two writes.

Code: Select all

;No indentation for the instructions, but you'll get the point.
lda #$20
sta $2006;Sets the high byte of the address $2007 will write to.
lda #$00
sta $2006;Sets the low byte of the address $2007 will write to.

sta $2007;Writes #$00 to PPU address $2000. (which is the first tile of the first name table)
lda #$FF
sta $2007;Writes #$FF to PPU address $2001. (which is the tile to the right of the first tile)
You'll see that every write increases the destination address by one. This is so you don't have to keep setting $2006 which is slow. It's also possible to make the destination address increase by 32 each write. This is so you can write a column of tiles. (256/8 = 32 tiles across. So each write will give you the address of the tile below the last one written)

In any case:

You know that your metatiles contain a reference to 4 actual tiles.

After setting the name table address with $2006:

1. You load the first metatile in your screen's index number.
2. You load the top left tile of that metatile using the index.
3. You write this to $2007.
4. You load the top right tile of that metatile using the index.
5. You write this to $2007.
6. load the second metatile in your screen's index number.
(Why? Because the other two tiles in the first metatile refer to the row of tiles BELOW the one you're dealing with)
7. Repeat steps 2-5.
8. Load the third tile... etc etc etc until the entire of the first row is written
9. Load the first metatile in your screen's index number AGAIN.
10. Load the BOTTOM left tile of that metatile using the index.
11. You write this to $2007.

And from there you should be able to figure out the rest for tiles, but probably not attributes. Reenable rendering when you're done writing to $2007, and you'll see the result.

There are ways to load each metatile in the screen only once, but make some code that is easy to do and works before you get clever.

For attributes, you do kind of the same thing. Write the address of the attribute tile you want to update to $2006, then write the actual attribute to $2007. Because of your metatile format, this might actually be really easy for you to figure out. (It's hard as hell to do in my format :lol: ... I digress)

That's... about all I will say. Good luck! Try it, and post some code if you get stuck!
Kasumi, thank you so much for this detailed explanation; loading a screen doesn't seem a little tough anymore! :D

It's about to become interesting though... I have to remove the loading of the nametables and replace that with a combination of your post and tokumaru's post he linked me to in this thread. Yes, this is taking me a long time to complete, but I feel blessed by yall's help... so thank you tokumaru and Kasumi! :D

Kasumi wrote:I've never asked, will your game scroll? If yes, hopefully only in one direction at a time? If no.. :?
Yes, it will scroll only horizontally. :)

Posted: Thu Dec 15, 2011 1:37 pm
by unregistered
So now I have two arrays... firstRow and secondRow. Each are 32bytes wide. There's also an array called screenArray; it is 240 bytes wide. I want screenArray to hold the contents of firstRow and secondRow. I dont know how to do this in 6502 assembly; could you help me with this? : )

edit: ...would I have to create two for loops like

Code: Select all

for (int x := 0; x < 32; x++) {
    screenArray[x] = firstRow[x];
}

for (int x := 33; x < 64; x++) {
    screenArray[x] = secondRow[x];
}

Posted: Thu Dec 15, 2011 3:21 pm
by Kasumi
Load the values in firstRow and secondRow, and store them to screenArray?

Code: Select all

loop:
   ldx #$1F
   lda firstRow,x
   sta screenArray,x
   dex
   bpl loop
loop2:
   ldx #$1F
   lda secondRow,x
   sta screenArray+32,x
   dex
   bpl loop2
edit: Oooh, here's a faster way to do the above:

Code: Select all

loop:
   ldx #$1F
   lda firstRow,x
   sta screenArray,x

   lda secondRow,x
   sta screenArray+32,x
   dex
   bpl loop
Whenever you want to load one thing and put it someplace else, just use lda and sta. There's no trick to it.

Bonus:

If firstRow and secondRow are stored like this:

Code: Select all

firstRow:
   .db $00 $01 ;etc etc 32 bytes
secondRow:
   .db $20 $21
;That is, they are stored such that there are no bytes between them
You can just do this:

Code: Select all

   ldx #$3F
loop:
   lda firstRow,x
   sta screenArray,x
   dex
   bpl loop
Though actually, that's slower than the above.

Edit in response to your edit: :o
edit: ...would I have to create two for loops like
Code:

for (int x := 0; x < 32; x++) {
screenArray[x] = firstRow[x];
}

for (int x := 33; x < 64; x++) {
screenArray[x] = secondRow[x];
}
Almost.

secondRow is 32 bytes long. secondRow[0] refers to the first byte of secondRow. So that second loop can't work. X starts at 33 (which would be secondRow[33]) which is either the third row's data, or unknown data.

Also, you can't start X at 33. You stopped at a value < 32 in the first loop, therefore you have never written the 32nd byte of screenArray if X starts at 33 in the second loop.

Posted: Thu Dec 15, 2011 3:46 pm
by unregistered
YES!! Thank you so much Kasumi! :) Spent a long time on my edit... sorry, I didn't see your post.

edit: Ahhh! Ok, thank you, I see what you are saying. :D
for the second loop:

Code: Select all


for (int x=0; x<32; x++) {
    screenArray[x+ #32] = secondRow[x];
}

Posted: Thu Dec 15, 2011 4:18 pm
by Kasumi
Yep, you got it.

Just some additional info: The reason I went down in my asm code, not up (like the C code) is to avoid an extra instruction.

Code: Select all

   ldx #$00;If you go up in a loop like this
loop:;You need a cmp.
   lda firstRow,x
   sta screenArray,x
   inx
   cpx #$40;If X is < #$20
   bcc loop;Go back to loop
That cpx takes 2 cycles every time. That loop runs 64 times. That's 128 cycles of unnecessary action.

Avoiding extra actions is also why this was faster than the first and last thing I posted:

Code: Select all

loop:
   ldx #$1F
   lda firstRow,x
   sta screenArray,x
 
   lda secondRow,x
   sta screenArray+32,x
   dex
   bpl loop 
The first thing I posted had two loops, so dex was done 64 times compared to the 32 for this. The second thing would have also run dex 64 times.

Not that you should worry about optimization a lot right now, but when you're writing loops keep that sort of thing in the back of your mind.

Posted: Thu Dec 15, 2011 5:17 pm
by unregistered
Kasumi wrote:Just some additional info: The reason I went down in my asm code, not up (like the C code) is to avoid an extra instruction.

Code: Select all

   ldx #$00;If you go up in a loop like this
loop:;You need a cmp.
   lda firstRow,x
   sta screenArray,x
   inx
   cpx #$40;If X is < #$20
   bcc loop;Go back to loop
That cpx takes 2 cycles every time. That loop runs 64 times. That's 128 cycles of unnecessary action.

Avoiding extra actions is also why this was faster than the first and last thing I posted:

Code: Select all

loop:
   ldx #$1F
   lda firstRow,x
   sta screenArray,x
 
   lda secondRow,x
   sta screenArray+32,x
   dex
   bpl loop 
The first thing I posted had two loops, so dex was done 64 times compared to the 32 for this. The second thing would have also run dex 64 times.

Not that you should worry about optimization a lot right now, but when you're writing loops keep that sort of thing in the back of your mind.
Kasumi, thank you!!!!!!! :D I'll try to keep that in the back of my mind. :)
*edited