8x16 and whatever else unreg wants to know

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

unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

tokumaru wrote:... for what purpose would you be using these oddRow and evenRow variables you speak of?
In my code idea there are two rows each 32 bytes. Then there is the screenArray; 240 bytes. I'm trying to fill both rows with values for collision... then add them both to screenArray... then clear oddRow and evenRow and fill them both again with new values for collision... then add them both to screenArray...etc.

edit: ok, I found the first mention of my plan on page 29. That was in December but I'm still learning and building; getting better. :)
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

I'm still confused.

oddRow and evenRow have to be RAM, otherwise you wouldn't be mentioning putting new values in them.

This being true, why do you want to put anything in them only to move them someplace else? Just put the values you will load (inevitably from ROM) directly into ScreenArray. Is there any reason for that first step of putting the values into oddRow and evenRow? What do you plan to do with ScreenArray? You're putting things here to do what with them? Load a value from them to check collision, or store them to the PPU? I've only got part of your plan.

The response I made to the post you linked made the assumption that the row labels were data in ROM. Your plan seems to be different, so help me understand all the steps.
Should I start creating the screen with oddRow or evenRow? Is that top line up there line 0 - even - OR line 1 - odd?
I don't know. Isn't it your data format? You define what's stored, where it's stored, how it's stored, what it's called and what it does.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

I'm as confused as Kasumi is...

The way you are asking makes it seem like there's only 1 way to do things, and that this way always uses these variables you mentioned. But actually, collision detection can be done in a thousand different ways, and we have given you some ideas to help shape the solution you'll be using in your game.

But since it's your game, everything is ultimately your choice and your design. Particularly, I don't remember everything we talked here, and I don't know exactly what solution you used, so if you want very specific help with your implementation you'll need to give us more details about how you're doing things.

All this data moving seems unnecessary to me as well, there must be a way to decode the maps from ROM into ScreenArray directly. For us to discuss that, you have to tell us how the maps and collision info are stored in the ROM, and what you want ScreenArray to contain.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

Kasumi wrote:why do you want to put anything in them only to move them someplace else? Just put the values you will load (inevitably from ROM) directly into ScreenArray. Is there any reason for that first step of putting the values into oddRow and evenRow?

I thought loading two rows of stuff would be hard, but still possible for me to do. And I thought that once I completed that it would be easy to make a loop to run it again. Now, I see your point! :) It would be much faster if I wrote to ScreenArray directly.
Kasumi wrote:What do you plan to do with ScreenArray? You're putting things here to do what with them? Load a value from them to check collision, or store them to the PPU? I've only got part of your plan.
I plan to use ScreenArray to check collision and to set the PPU. I'm going to try writing the values directly into ScreenArray. :)
tokumaru wrote:The way you are asking makes it seem like there's only 1 way to do things, and that this way always uses these variables you mentioned. But actually, collision detection can be done in a thousand different ways, and we have given you some ideas to help shape the solution you'll be using in your game.
Yes, ok, then I need to create my way... just one of the thousand.

Thanks Kasumi and tokumaru! :D
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

I have a question. There are four variables that recieve a 0-or-1 value at about the same time. Then I want to reassign each variable a second-more-important value depending on their first 0-or-1 value. It seems to me to be good to reuse the same variables for these values because it is all going to be changed a whole lot throughout the game; reusing the same four variables for these 8 values seems like maybe a good idea to me. But, then I dont know... :? ...I think it is bad that the four variables recieve their 0-or-1 value at about the same time because that initial valuing that happens at about the same time... making it rough to use a loop to cycle through each of the four values. And I thought I could just unroll the loop and copy the middle code three more times but I dont know. :? Maybe that's what I should do? Get the code to work... and then improve it. Do yall have any helpful ideas for me about this?

edit: In asm6 I know you can have multiple + labels... it just goes to the first + it finds. Can I also have multiple labels like +xyz and +xyz?
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Both asm6 and ca65 support cheap local labels that are visible only between two ordinary labels. Names of such labels start with an @ sign. For example, you could do something like this:

Code: Select all

do_something:
  blah
  blah
@loop:
  blah
  blah
  bne @loop
  rts

do_something_else:
  blah
  blah
@loop:
  blah
  blah
  bpl @loop
  rts
(The ca65 manual uses the term "cheap" to denote @labels because ca65 also has .proc, a more structured way to make labels visible only within a given scope.)
User avatar
Yggi
Posts: 29
Joined: Wed Dec 22, 2010 9:14 am
Location: Germany

Post by Yggi »

In asm6 you can have many different + and - labels like this:

Code: Select all

  LDX #$10
--
  LDY #$10
-
  DEY
  BNE -
  DEX
  BNE --
The - and -- are treated just like normal labels but can be reused. You can also have multiple + labels. But using many of these labels can quickly make your program messy...
But they're still much better than the ugly anonymous labels in ca65 which makes your code really hard to understand...

You can also use temporary labels like tepples' already said. But unfortunately you can't use these temporary labels together with +/- so this code is not compileable:

Code: Select all

  code
  @bla
    code
    -
      more code
      BNE -
    even more code
    BEQ @bla
The +/- labels destroys the scope of the @bla label, so you'll get an error that @bla is an unknown label.
Last edited by Yggi on Fri Mar 16, 2012 2:48 pm, edited 1 time in total.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

unregistered wrote:Can I also have multiple labels like +xyz and +xyz?
Yes. Anything starting with "+" or "-" can be reused. When you refer to those labels, the nearest one will be used.

Sorry if I don't have anything to say about the other question, but I found it very confusing. Wouldn't you rather present us the problem in a more abstract way instead of asking details about a possible solution that exists only in your head? I mean, you seem to have some idea of how to go about your problem because you gave some thought to it, but since we don't know how or why you came to that conclusion it's hard for us to visualize the problem.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

unregistered wrote: There are four variables that recieve a 0-or-1 value at about the same time. Then I want to reassign each variable a second-more-important value depending on their first 0-or-1 value. It seems to me to be good to reuse the same variables for these values because it is all going to be changed a whole lot throughout the game; reusing the same four variables for these 8 values seems like maybe a good idea to me.
I think this is too abstract. I want you to give what the goal of the code is, and then I can think of method to do it. You can also give a goal + a method, and then it's easier for me to tell you, "Yeah, that's great. That will work for that." or "I'd do this instead, but that will work." or whatever. But method without goal means I have to say almost anything will work, or I have to guess at what the goal is. Should you use one byte of RAM for related values? Sure, why not?

In any case, here's a couple of things I'll say based on what I think you're asking about.

You've got a set of four variables. They've got a format like:

%0000XYYY
Where YYY is only set to some other value if X is true (or only set if it's false. Doesn't really matter.) Y could be a value of 0 or 1 (in which case it would only take 1 bit.) or Y could be 0-8 (with 3 bits as in the example. I assumed it took more because you didn't say that Y was specifically 1 or 0 like you did with what I'm calling X.)

If both X and Y can really only be 0 or 1, you could actually use just one byte for all four of your variables.

%XXYYZZAA
Where XX = the first and second bit of the first variable,
YY = the first and second bit of the second variable,
etc. This setup may make your code a small bit slower. Does it matter for what your goal is? Will these values be referenced a lot of times in a frame? Optimizing for RAM, or optimizing for speed? What's most important?

The (possibly only slightly) faster way to do something like this

%XYYYYYYY This way you keep the 4 variable setup you have now, and can quickly check your first value (X) to see if you need to set your second value (Y). It also allows you to use up to 7 bits for Y, but you can only use one of them. It doesn't matter.

Code: Select all

   lda variable1
  bpl nosetmoreimportant;If bit (X) is not set, don't reassign second
  ;whatever code sets the more important variable

nosetmoreimportant:
You could even just use more bytes if say... the second more important variable needed to use 8 bits. It'd make no difference, unless you're short on RAM. It all depends on what your goal is. If, for instance, these variables don't need to be persistent across frames, it matters almost zero how much RAM you use. You could use like 16 bytes of RAM. It wouldn't matter because once the routine is finished, they're free again. You say they'll be changed a lot, but I don't know if that means they'll need to be persistent.

I'd like a goal to give better advice.
Get the code to work... and then improve it. Do yall have any helpful ideas for me about this?
Or tell us what the code is supposed to be doing, so we can really say if the method you're suggesting is a good one.

For the record, here's what some of one of my byte format documents looks like:

Code: Select all

$060B = XXXYYYZZ
		XXX = Subpixel X
		YYY = Subpixel Y
	
		ZZ = Controller to read from.
			ZZ = 0: Controller 1
			ZZ = 1: Controller 2
			ZZ = 2: Controller 3
			ZZ = 3: Controller 4

$060D = X Velocity unscaled

$060E = Direction
		X0000YYY
		X = Vertical Orientation
			X = 0: is not vertically flipped
			X = 1: is vertically flipped
		YYY = Direction
			YYY = 0: is facing up
			YYY = 1: is facing up-right
			YYY = 2: is right etc.
;This may seem a tad confusing. If X is 1 and Y is 2, he'll face right, but be upside down (feet in the air). if X is 0 and Y is 2, he'll face right and have his feet on the ground. To make him roll, X will stay the same value, and Y will increase (or decrease) by one, until it wraps. He can roll such that his feet will touch the ground while he's facing right, or such that his feet will touch the ground while facing left.
That's at least how I document my formats, it may not be the standard way, though. A 0 means the bit is free for whatever else I can pack into the byte. No further documentation means the entire byte is used for the one value. This format may help you keep track of things, or possibly communicate your ideas, or it may not help at all! :D But here it is.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

tepples wrote:Both asm6 and ca65 support cheap local labels that are visible only between two ordinary labels. Names of such labels start with an @ sign.
tepples, thank you for reminding me about the local labels starting with @. I was thinking that labels with + or - at the front were local labels. Ha hahaha :P <-- look I'm silly.
Yggi wrote:The +/- labels destroys the scope of the @bla label, so you'll get an error that @bla is an unknown label.
Thank you Yggi for your help and especially your note that +/- destroys scope of local labels! :)

tokumaru wrote:
unregistered wrote:Can I also have multiple labels like +xyz and +xyz?
Yes. Anything starting with "+" or "-" can be reused. When you refer to those labels, the nearest one will be used.
I was hoping for this reply. I am excited! :D
Sorry if I don't have anything to say about the other question, but I found it very confusing. Wouldn't you rather present us the problem in a more abstract way instead of asking details about a possible solution that exists only in your head? I mean, you seem to have some idea of how to go about your problem because you gave some thought to it, but since we don't know how or why you came to that conclusion it's hard for us to visualize the problem.
Yes. :( I'm sorry for asking something that is hard for yall to visualize. My sister suggested I make more notes to myself and after that when I have a real question ask that. That was a good suggestion! :)
Kasumi wrote:I think this is too abstract. I want you to give what the goal of the code is, and then I can think of method to do it. You can also give a goal + a method, and then it's easier for me to tell you, "Yeah, that's great. That will work for that." or "I'd do this instead, but that will work." or whatever. But method without goal means I have to say almost anything will work, or I have to guess at what the goal is. Should you use one byte of RAM for related values? Sure, why not?

In any case, here's a couple of things I'll say based on what I think you're asking about.

You've got a set of four variables. They've got a format like:
If both X and Y can really only be 0 or 1, you could actually use just one byte for all four of your variables.
All of this is important to me; Kasumi, thank you so much for this excellent help! :D My mind is growing. Good things like this:
Kasumi wrote:This setup may make your code a small bit slower. Does it matter for what your goal is? Will these values be referenced a lot of times in a frame? Optimizing for RAM, or optimizing for speed? What's most important?
My goal is to see this collision detection work well. (Optimizing for speed. right now... I think) And to find out why there are so many Can't determine address. error lines when I try to assemble my nes file. But, that is for only me to worry about right now. :)

I will come back and reread especially Kasumi's post many many times.
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Post by Kasumi »

My goal is to see this collision detection work well.
I don't quite see the relation to collision detection.

But sure, I can sure talk about it. It's actually really easy and fast as long as you don't handle slopes, and don't have things like tiles you can jump up through or tiles you can drop down through.

You only really need to check 6 points to be TOTALLY safe, or 4 if the shape of your character never changes and he is smaller than the size of the collision tile for both X and Y. If he's say... 24 pixels tall with 16x16 collision tiles you have to check one more point. You also need to check more if your character moves more pixels in a frame than the size of your tile. For instance, he's capable of moving 9 pixels in a frame, but your collision tiles are only 8 wide.

Obviously, you first gotta find out whether or not the tile you're working with is collision enabled. I can't especially help with that unless you make a post about your current tile format. Post about that, and I can write a book for you about that.

I personally keep 4 screens of 32x32 metatiles in a page of RAM, which are updated when the game scrolls to a new screen. This means all my screen decompression happens once and only on a frame when the character passes a screen boundary.

The collision detection and parts of my code that tell the PPU what to draw always pull from this RAM, where it is much easier to figure out the math for me than pulling directly from the data in ROM.

I load the 32x32 tile from RAM, I find out the 16x16 tile I want in it. Then I know if I should eject or not.

It works exactly like this:

Code: Select all

;Ignore the <'s, it's a nesasm thing.
	lda <xhigh;Zero Page RAM I put any high X position into
	ror a;puts the lowest bit of the high x pos into the carry
	
	lda <yhigh;Zero Page RAM I put any high y position into
	ror a;puts the lowest bit of the high y pos into the carry
	;and puts the x bit into the high bit of the accumulator
	
	ror a;Now the low x and y bits are in the high bits accumulator
	
	and #%11000000;Removes the other junk in the accumulator
	
	sta <reservedE;Temp RAM. The highest bits of it now contain
	;which screen I'll read from RAM. Each screen is 64 bytes long, because it contains 8x8 32x32 metatiles. 
	
	lda <xlow
	lsr a
	lsr a
	lsr a
	lsr a
	lsr a;divide by 32, since I'm trying to get a 32x32 metatile. 
	;The other bits of precision don't matter.
	
	ora <reservedE;This combines my "which screen" bits with the X offset in RAM.
	
	sta <reservedE
	
	lda <ylow
	lsr a
	lsr a
	and #%00111000;This takes away all unnecessary bits from
	;my y position
	ora <reservedE;I know have the offset in RAM that I need to load my 32x32 tile from.

	tay;Y contains the address of the 32 x 32 metatile to look up

	lda $0500,y;loads 32 x 32
	tay;Y contains the 32 x 32 tile number
The tricky part is actually getting the 32x32 tiles into RAM in the first place, but you may not even need to do that depending on how your data is stored.

I then use a series small series of branches to determine which part of the 32x32 tile I'm in. Topleft, Topright, bottomleft, or bottomright. Once I know that, I load the tile and use its format to determine whether it's a collision or not.

Here's how I eject when I know the current tile is collision enabled

Code: Select all

;Ejecting up/left
lda lowbyte
and #%00001111
clc
adc #$01
sta offset

rts
You want to eject left while traveling right. So imagine the right point of your character has just entered the first pixel of a tile. It's anded position would be 0. In this case, you obviously want to eject one. If you're going super fast, you'll end up further in the tile, so the and will be higher and you'll always eject one more than that. Easy. jsr to the routine, subtract offset from your character's position. (It should be set to 0 if the collision routine detects the current tile is not a collision tile.) You can even use the offset variable the routine returns to find out whether or not there WAS a collision if you want to do that to stop a walking animation or something.

Code: Select all

;Ejecting down/right
lda lowbyte
and #%00001111
eor #%00001111
clc
adc #$01
sta offset

rts
This one is mostly the same, except it has an eor. Say you're traveling left and hit the first pixel of a tile. That's actually pixel $0F, but you only want to eject one! The eor makes $0F equal to one, then it works the same as before! As before, just write a 0 to offset if you've discovered the current tile is not solid. Jsr to routine, then add offset to player's position.

This works for any size tile that's a power of two. Just change the ands and eor to the number of bits your tile takes up.

If you're traveling left, move the player using the current speed value. You may be in a wall. You check the top and bottom left points of your character, and eject right. (add offset) If you're traveling right, check the top and bottom right points of your character and eject left. (subtract offset) you'll never be in the wall for a frame like Mario, and this will certainly be fast enough for how few tiles you'll need to check.

For ejecting up while falling you check the bottom left and right points and subtract offset from the player's position.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

Pardon me Kasumi, but this is just crazy... doesn't make any sense.

0 to 31 ok, this is 32 values
32 to 63 now this is 31 values
64 to 95 ... 31 values
96 to 127 ... 31 values

How am I susposed to skip 32 values when every row beyond the first has only 31 values? :? It doesn't work yet. :( What am I missing?
Shiru
Posts: 1161
Joined: Sat Jan 23, 2010 11:41 pm

Post by Shiru »

32 to 63 is 32 values, like 4 to 7 is 4 values: 4,5,6,7.
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

ooooooh! Yes, thanks Shiru!! :D
unregistered
Posts: 1318
Joined: Thu Apr 23, 2009 11:21 pm
Location: cypress, texas

Post by unregistered »

Kasumi wrote:I personally keep 4 screens of 32x32 metatiles in a page of RAM, which are updated when the game scrolls to a new screen. This means all my screen decompression happens once and only on a frame when the character passes a screen boundary.
Sounds like a great plan! :D How many screens of 16x16 metatiles could fit in a page of RAM? We're ending 2 hours early today... and that's now... so I'll think more about this on Monday.
Post Reply