I'm working on turning sprite to tile coorinates and I'm having trouble with the maths involved. What exactly are my options here? At first for a simple test I'm first of all allowing the movement of the player. Then checking the direction and branching to either an horizontal collision check or vertical depending on direction. From there I turn sprite coords into tile by the (Y/8)*32+X/8 via lsr asl combo. It sort of works until I realized that for that I need it to be 16 bit as the uncompressed collision map is. What are my options here? Do I need to turn the Collison map into bit values where 1 bit = 1 tile? But then I would still need the math to have that 16 bit number, right?
-Thanks, zkip.
Can you provide a bit more context about how you've structured your map data? Is it designed for single screen, scrolling, multi directional scrolling? *edit* What are the dimensions of a map? How big are your tiles, and do you use metatiles?
Single screen. Simplest you can get. I do plan on later doing more but I'd assume for relearning purposes the simplest would be most understandable without worrying about scrolling, tile types,metatiles, etc getting in the way.
The nametable data is arranged in such a way that it can also be used as the Collison map.
That's a good approach to start with single screen first. You could structure your collision data any way you like. Since you're just starting out, I'd recommend keeping it simple. I'd probably keep an array in ram of 16 * 15 bytes, where each byte contains information about a single, attribute sized tile (16x16 pixels). This byte could be a bit field where one bit is used for "solid," another for "hurt," and perhaps other information relevant to your game. To index such a map, you might do something like:
Code:
MAP_SOLID = %00000001 ;a mask for the solid bit. you can add other masks for other information
;this could be in zp used as parameters for a routine to look up map data
map_x: .rs 1
map_y: .rs 1
;this could be in zp, these are just temporary values for the routine to use.
row: .rs 1
column: .rs 1
;this would be in RAM
map_data: .rs 16 * 15
;this would be in a code bank
;Here's a routine for getting the byte from the map based on 8 bit X and Y (single screen coordinates, 16 bit not needed)
;It expects map_x and map_y to contain a coordinate in screen space (pixels)
;It will return with the accumulator containing the byte describing the tile that map_x and map_y intersects.
get_map_byte:
;divide map y by 16 to get your row
lda map_y
lsr
lsr
lsr
lsr
sta row
;divide map x by 16 to get your column
lda map_x
lsr
lsr
lsr
lsr
sta column
;now we compute location in map_data by row * 16
lda row
asl
asl
asl
asl
;now add the column on
clc
adc column
;use computed index to look up byte
tax
lda map_data,x
rts
;Now you can use this routine (elsewhere in your code) to get information about a tile on the screen.
;load some arbitrary coordinates into the map_x and map_y params. You'd probably use a collision point under your character's feet or somewhere else around them depending on the direction they are going.
lda #100
sta map_x
lda #120
sta map_y
jsr get_map_byte
and #MAP_SOLID
beq not_solid
;do something if tile is solid
not_solid:
Hope that helps!
*edit* You could put your map data in ROM, too. Since it's in RAM in this example, you could have it change dynamically during gameplay, but you'd need to load useful data into it, first.
*edit* Forgot to demonstrate loading x and y coordinates into the parameters. Fixed.
Thanks for the detailed reply! Although, it looks like that is for a screen with 16x16 metatiles? I'm assuming in the case of collisions this method is easier? My current setup of the level is all 8x8 tiles. Which is why I was asking about the 16 bit. Away from computer right now, but from memory a 32x30 8x8 tile screen is far above anything accessible from 8bit registers.
Yeah---using tiles that are 16x16 in size, you can get away with only 8 bit indexing as in the example, so it is very simple. For indexing for 8x8 tiles for single screen, you'd have 32x30 (960 total) tiles, you can change the right and left shifts to only shift by 3 instead of 4 (divide or multiply by 8 instead of 16). Then when you compute the location in your map data, if you still use one byte per tile, you will have to extend into 16 bits (because if you have 32x30 tiles, one byte each, it'd be 960 bytes). If I get another sec soon I'll try to rework the example extending to 16 bit indexing.
Here's the example modified for the case you were interested in. 8x8 tiles, single screen map. Note this is just one way of doing it, probably the simplest to follow. You could of course come up with a collision map that really is one bit per tile rather than one byte per tile, then you'd need to do some more bit rotation and shuffling things around to get at the bit you want. But this approach is good for being able to easily expand to using multiple bits for each tile, for additional information like hurt, item, etc. etc.
Code:
MAP_SOLID = %00000001 ;a mask for the solid bit. you can add other masks for other information
;this could be in zp used as parameters for a routine to look up map data
map_x: .rs 1
map_y: .rs 1
;this could be in zp, these are just temporary values for the routine to use.
row: .rs 1
column: .rs 1
;fully computed 16 bit address of tile within map. this will need to be zp so you can use indirect addressing.
map_tile_address: .rs 2
;this would be in RAM (*edit* or ROM. Probably simpler to try it out in ROM first, make a 32x30 bunch of 0's and 1's with a define byte directive to define your solid/not solid map)
map_data: .rs 32 * 30
;this would be in a code bank
;Here's a routine for getting the byte from the map based on 8 bit X and Y (single screen coordinates, 16 bit not needed)
;It expects map_x and map_y to contain a coordinate in screen space (pixels)
;It will return with the accumulator containing the byte describing the tile that map_x and map_y intersects.
get_map_byte:
;divide map y by 8 to get your row
lda map_y
lsr
lsr
lsr
sta row
;divide map x by 8 to get your column
lda map_x
lsr
lsr
lsr
sta column
;now we compute location in map_data by row * 32
;first we load row into the lo byte of map_tile_address
lda row
sta map_tile_address
lda #0
;then we set the hi byte of map_tile_address to 0. Now we do a 16 bit shift (5 times, to do * 32) to compute the correct address.
sta map_tile_address+1
;now we do a 16 bit shift left to multiply by 32.
lda map_tile_address+1
asl map_tile_address
rol
asl map_tile_address
rol
asl map_tile_address
rol
asl map_tile_address
rol
asl map_tile_address
rol
sta map_tile_address+1
;now add the column on, sign extending the 8 bit column which we know is positive
clc
lda map_tile_address
adc column
sta map_tile_address
lda map_tile_address+1
adc #0
sta map_tile_address+1
;finally add on the base address of our map data
clc
lda map_tile_address
adc #<map_data ;(use #low(map_data) if using nesasm...)
sta map_tile_address
lda map_tile_address+1
adc #>map_data ;(use #high(map_data) if using nesasm...)
sta map_tile_address+1
;use computed index to look up byte
ldy #0
lda (map_tile_address),y ;note, nesasm uses [ ] instead of ()
rts
;Now you can use this routine (elsewhere in your code) to get information about a tile on the screen.
;load some arbitrary coordinates into the map_x and map_y params. You'd probably use a collision point under your character's feet or somewhere else around them depending on the direction they are going.
lda #100
sta map_x
lda #120
sta map_y
jsr get_map_byte
and #MAP_SOLID
beq not_solid
;do something if tile is solid
not_solid:
Thank you, you have been more than helpful to me. I have one more question and I think I'll have this. In the order of things you'd first let the player move. Then check for a collision and if true I've heard to "eject" the player. What exactly is this eject? Move the player a predetermined amount or does it mean move 1 pixel until the collision no longer exists?
An eject is essentially to figure out how many pixels to pop your character out of a tile. I usually use AND for this. I usually AND the coordinate with %00001111 to see how far a character is poking into the (16 pixel wide) tile, then I subtract this value from their coordinate (if you're moving in the positive direction on the x or y axis). Depending on the speed of your character, this may require additional logic to cover additional edge cases, but that's the most basic step for ejection.
*edit* I didn't cover the case for ejecting from moving the other direction. If I get another spare moment I'll try to illustrate that as well, though maybe tokumaru's linked post already covers this.
zkip wrote:
Move the player a predetermined amount or does it mean move 1 pixel until the collision no longer exists?
Neither. A predetermined amount doesn't work if objects move at variable speeds, and testing for collisions repeatedly after moving 1 pixel would use too much CPU time. You should move it the number of pixels that went into the solid block.
This post might help.
Quick Tip:
Move your character horizontally, and then check for collisions on the X axis.
Then move your character vertically, and then check for collisions on the Y axis.
If you try to move both at once, you'll never be able to properly determine if you landed on the top or side of a corner.
I see now. Thanks everyone. Also, thanks for that info darryl. I've always heard to do that but never known exactly why.
Here's a thought...
32 tiles accross, 5 bits from X and Y. Add to address of data = tile.
Code:
Lda #0
Sta Temp_High
Lda Y_position
And #$f8
Asl a
Rol Temp_High
Asl a
Rol Temp_High
Sta Temp_Low
Lda X_position
And #$f8
Lsr a
Lsr a
Lsr a
Clc
Adc Temp_Low
Sta Temp_Low
Ldx Which_Room
Lda Table_of_Map_Addresses_Low, x
Clc
Adc Temp_Low
Sta Pointer
Lda Table_of_Map_Addresses_High, x
Adc Temp_High
Sta Pointer+1
Ldy #0
Lda (Pointer), y
;equals the tile
Tax
Lda Collision_Array, x
Beq No_Collision
Jsr Eject
No_Collision:
This allows for multiple rooms, each with their own map.
GradualGames wrote:
Here's the example modified for the case you were interested in. 8x8 tiles, single screen map. Note this is just one way of doing it, probably the simplest to follow. You could of course come up with a collision map that really is one bit per tile rather than one byte per tile, then you'd need to do some more bit rotation and shuffling things around to get at the bit you want. But this approach is good for being able to easily expand to using multiple bits for each tile, for additional information like hurt, item, etc. etc.
I just now got around to messing around with the code you provided and I have one more question. This returns the 16bit position, but how exactly do I index that with the data I have in ROM? I've tried clc and adcing the high and low bytes of the address where the collision data lies, however this works for certain parts of the screen an the other parts are returning with arbitrary numbers such as 1f. Further more, this doesn't seem right to me. Surely there's another way to index it?
The 16 bit address should point directly to the byte you want that represents data for an 8x8(pixel) tile on a 32x30(tile) sized screen. Just don't change y and read that byte (as in the routine) and you can find out the data for that tile. Any time you want information about another tile on the screen just call get_map_byte again with a different X and Y coordinate. Since we have to look up something that goes beyond 256 bytes you have to use indirect addressing---the index register will typically be zero in this case. If there's a significantly better way of doing this, I'm eager to learn it, myself.
*edit* Perhaps you are asking about the array containing your map data. In the example, I suggested placing it in RAM. In this case you would need to load this array with data that makes sense, and you would gain the advantage of being able to change the data at runtime, easily. However, you can put this data in ROM, instead. Note I made an error (which I fixed yesterday) in the 16 bit example: I should have allocated 32 *30 bytes for map_data, not 16*15, which was for the earlier example.
The easiest thing would probably be to design a 32x30 map of bytes in ROM with data about your map (0's for not solid 1's for solid), and then read that.
I'm confused because for demonstration let's say I am putting it in RAM. In that example you're defining this here:
Code:
map_data: .rs 32 * 30
however, I don't see any references to it in the
get_map_byte routine. To my understanding, this would mean the data must be located at $0000 RAM?
zkip wrote:
I'm confused because for demonstration let's say I am putting it in RAM. In that example you're defining this here:
Code:
map_data: .rs 32 * 30
however, I don't see any references to it in the
get_map_byte routine. To my understanding, this would mean the data must be located at $0000 RAM?
Oops! I forgot to add on the address of map_data. I will fix the 16 bit example earlier. *edit* fixed. I put in some comments relevant to nesasm/asm6 syntax as well as I wasn't sure which you are using. *edit* note not all syntax differences were accounted for, particularly when reserving bytes in ram. I'll assume you understand that part---if not, let me know and I will clarify for your chosen assembler.
Thanks! I'm having quite a bit of trouble with this. The routine works great but now I'm having issues with the ejection. As a simple test I wrote collision for one side if the box using the method posted earlier. If I post the code could someone look through an see what's bugging it? I currently have it set up to instead add a predetermined amount because the EOR $0f produced some weird results. In certain tiles it jumped back too far. After some debugging I've found that once it made the collision, say it's X was $69. EORing that with $0F produced $68 IIRC. (Sorry for unclarity my computer doesn't have internet but the phone does so I'm going back an forth.) Thus, adding 69 + 1 to the X position.
Attached is the code in advance.
I am not yet familiar with tokumaru's approach using eor (as you describe in your asm file there), I'll let him comment on that technique. I can try to spin up a simple example that I'm familiar with, for now, however.
Code:
;If you're going right, or down, and you're considering a point on the right, or bottom, of your character.
lda coordinate ;assumes that you already computed the new position, you might be poking into a tile. also assumes that you know you ARE poking into a tile (e.g. you tested a map byte and it was SOLID)
and #$0f
sta temp1 ;now we know how far that point is poking into the tile. Works for speeds up to 7, I believe. 8 and higher would pop to the other side of the tile.
sec
lda coordinate
sbc temp1
sta coordinate ;at this point the coordinate should be ejected
;If you're going left, or up, and you're considering a point on the top, or left of your character. Same assumptions concerning having performed a collision test apply.
lda coordinate
and #$0f
sta temp1
sec
lda #16 ;we want to know how far we're poking in from the other side
sbc temp1
sta temp1 ;now this is how far you need to pop out
;actually pop out, this time from the left or from below.
clc
lda coordinate
adc temp1
sta coordinate
Hope that helps, I'll let others chime in with alternative or improved techniques. I should go read tokumaru's thread
*edit* I realized I defaulted to 16x16 tiles once again. for 8x8, you'd use and #$07, and lda #8 instead of 16 when doing the opposite case. The speeds of your character would have to be 3 or smaller to not pop to the other side, with this technique.
*edit* Another comment I'll make is, when you actually apply this technique, you may have to toy with which collision points around your character work the best, and how many of them you need relative to how wide your character is in comparison with the collision map you're using. It usually takes quite a bit of fiddling to get right, and it seems it is different for each game.
EOR $0f is just a shortcut for calculating 15 - n. You can do in one instruction what would normally need 3 instructions and a temp memory position.
tokumaru wrote:
EOR $0f is just a shortcut for calculating 15 - n. You can do in one instruction what would normally need 3 instructions and a temp memory position.
Ah, cool! I'm going to try this next time I implement ejection. I'm also interested in understanding the math behind it. I wouldn't have thought of this on my own, I don't think---so far, my approach has been to break everything down into the clearest steps possible. I'm ready, now, to start diving into trickier stuff!
In this case, for me, it was more a matter of observation than actually knowing the operation would work. Whenever I want to find a good way to turn something into something else I write down a table with both versions of some sample data and start thinking of the operations that could give me the desired result. In this particular case, I simply noticed that x EOR #$0f would give the same result as 15 - x.
Now I understand that since EOR inverts bits, and $0f has all the bits set, inverting bits always means turning them into 0s, which is effectively the same as subtracting those bits.
I had this working great, but when I tried to implement it into a platformer things went crazy. I'm terribly sorry that I'm not at the computer right now, however I'm hoping it's one of those problems that can be diagnosed without code. Basically at the beginning of the logic after checking the controller I call a routine that I call checkground. This routine checks the 2 points at the bottom of the sprite and if solid it first sets the player-on-ground flag to one, then it ejects the player however many pixels it went in. Otherwise it will set the flag mentioned earlier back to 0. Now, directly after this I check this flag and if 0 set the YSpeed to 2 which makes the player have gravity, else set it to 00 which stops the player. (Yspeed is added to the players Y each frame.) With all of that said, it works. But there's maybe two or so frames where it shows the player sink into a tile, and on the next it's corrected and it works as it should. Is it the order that I do things? Code is in the order of the way I described it.
Thanks, zkip.
You should do all of your velocity/acceleration code prior to doing an ejection check. That is always compute where the player is going first, then eject, before flagging your nmi routine that anything should be drawn. If you're still getting stuck in a tile, you might need to adjust which collision points you are examining, or there might even be an off-by-one error in the ejection code. The fact that sprites draw at Y + 1 often can cause confusion.
*edit* I would add if you're not using acceleration and sub-pixel precision for your first experiments, you should probably always keep the y velocity at your desired value of 2. The ejection should take care of the player staying flat against the tile before each frame is rendered. *edit* then, when the player is over a tile that is not solid (for all of the collision points you are considering), it should then start falling at the desired speed.
I suppose I do need acceleration to simulate a jump. I tried this:
Code:
procesesjump:
lda playerjmpflag
beq .r
lda jumptimer
sec
sbc player-yspeed
sta player-yspeed
dec jumptimer
.r
rts
and set that from the button code:
Code:
bwaspressed:
lda #$10
sta jumptimer
However, this was not producing what I wanted. Any tips? Do note that I am taking care of that jump flag later in the code. The problem is the jump is too fast I think.
To simulate a jump without having your y velocity increase way too fast and have your character fly off the screen, you'll need to use sub-pixel precision. Here's an example I recently posted over in general stuff. I have modified it so that the y coordinate is only 8 bits, with 8 bits sub pixel precision.
Code:
;Note I picked all these constants arbitrarily, I wouldn't know without running the code what the jump would look like. I would then tweak these values til I get the arc that I want.
ACCELERATION = 100
START_JUMP = -50
;zp variables
y_coordinate: .res 2
y_velocity: .res 2
;when you detect A button and the character is standing on something
lda #<START_JUMP
sta y_velocity
lda #>START_JUMP
sta y_velocity+1
....
;on each frame. You would always do this--jumping just sets y velocity to an initial value, landing on a tile (not included in example) would set y velocity to 0. Ejection would keep it at 0 if you're standing on a tile.
;Add 16 bit y velocity to 16 bit y coordinate. 8 bit world coordinates, 8 bit sub pixel precision
clc
lda y_coordinate
adc y_velocity
sta y_coordinate
lda y_coordinate+1
adc y_velocity+1
sta y_coordinate+1
;Now add acceleration to y velocity
clc
lda y_velocity
adc #<ACCELERATION
sta y_velocity
lda y_velocity+1
adc #>ACCELERATION
sta y_velocity+1
;note, y_coordinate+1 represents your y coordinate in world coordinates. For a single screen game, no adjustment needs to be done so it is also your y screen coordinate.
;note also you would do all your ejection after the above code executes, resetting y_velocity back to 0 if you're standing on a tile. If you're not standing on a tile, then y_velocity will gradually increase as the sub-pixel byte is incremented by velocity, increasing inspeed as velocity has acceleration added to it on each frame.
;What you'll see happen is y_velocity will slowly increase up to 0, where your character will be at the peak of its jump, then it will gradually increase and the character will fall.
Is that the *only* way to do it? I'm not a copy paste guy, so I don't wanna copy code I don't really understand. Do you, or someone else care to elaborate on why that works or even what sub pixel precision is? Furthermore, what other NES games might use this method?
Anything with acceleration and deceleration (which includes non-scripted jumps) will use sub-pixel precision. Sub-pixel precision is exactly what it sounds like: a way to represent positions and speeds smaller than one pixel. You know how in an 8-bit value, each unit is worth 1? 1 is worth 1, 2 is worth 2, and 255 is worth 255. If you add a byte after this one to create a 16-bit value, each unit in that byte is worth 256. 1 is worth 256, 2 is worth 512, 255 is worth 65280. Well, you can do the same thing on the other end and add another byte BEFORE the one where each unit is worth 1, and each unit in that byte will be worth 1/256, so you can use it to represent fractional values between 1/256 (0.00390625) and 255/256 (0.99609375), in increments of 1/256.
For example, say that a character is moving right at 128/256 pixels per frame (the fractional byte of the speed is 128, which is halfway to 256). That's 0.5 pixels per frame. Say that this character is exactly at position 230, meaning that the fractional byte of the position is 0. In the first frame, when you add 128 to 0, nothing visible happens, because the whole part of his position is still 230. But in the next frame, when you add 128 to 128, the factional byte overflows and wraps around to 0, and the overflow is carried over to the integer part of the position, changing it to 231. Keep following this pattern and the character will continue to move 1 pixel every other frame, which is the same as moving 0.5 pixels per frame.
You don't normally do anything with the fractional part of these numbers besides adding, subtracting, and propagating overflows/underflows into the higher bytes. They don't mean anything for sprites, and shouldn't be used for collisions either. They're only there to make movements smoother.
Part of the problem is that neither the C Standard nor POSIX nor the Windows ABI specifies a 24-bit integer type. Therefore, it's hard to find a type that's 8 bits of subpixel, 8 bits of pixel, and 8 bits of screen. I think Genesis games just fall back to 16 bits of subpixel in order to use 32-bit math. That's fine on 68000, which can load the upper 16 bits of a 32-bit int with little overhead, but I don't find it so practical on 6502.
You could try the SMB3 approach: 16 bit integers with 4 bits of subpixel, 8 bits of pixel, and 4 bits of screen.
tepples wrote:
Part of the problem is that neither the C Standard nor POSIX nor the Windows ABI specifies a 24-bit integer type.
So a good Pascal compiler targeting the 6502? Subrange Types could perhaps be a solution to this.
Suppose I wanted to make it that way; 8bit. 4 bits of pixel and 4 of subpixel. Before I try this and possibly screw myself over, is that plausible for 1 screen? Something like using bit math to separate the two nybbles into temp zero page RAM then add them as if they were 16bit? Would I then catch the overflow from the carry and then add it to the lower nybble? But how would the carry even get set because it wouldn't go over $ff. Would it be considered "hackish" if I just check if the lower nybble is larger than $0F and manually set the carry flag?
In my calculations which are probably wrong, this would make $48 essentially be 4.5?
zkip wrote:
4 bits of pixel
You'll be able to move a total of 16 pixels. You'll probably need more bits than that for a game.
zkip wrote:
But how would the carry even get set because it wouldn't go over $ff. Would it be considered "hackish" if I just check if it's larger than $0F and manually set the carry flag?
Why do you need the carry flag?
Joe wrote:
You'll probably need more bits than that for a game.
This is for the
acceleration of the player, not the actual coordinates. I'm pretty sure I won't need more.
Joe wrote:
zkip wrote:
4 bits of pixel
You'll be able to move a total of 16 pixels. You'll probably need more bits than that for a game.
For
Sonic, maybe. But is there anything in, say,
Super Mario Bros. 3 that moves more than +/- 8 px/frame, crossing the screen in a half second? The fastest thing I remember from that game is the large cannonball from the tank levels in World 8 "Dark Land". I've read its scrolling engine goes haywire if Mario exceeds 4 px/frame.
I'm still struggling with this.
Just getting around to trying the method described earlier and I'm back in the same boat. Granted, the player has more smooth gravity, but the jump is still the same. It's sort of a "snap" jump. Adding the constant as you described in the code as START_JUMP still makes this same problem. I adjusted the values to fit this scenario, but it's still that same "snap" jump as I had to begin with. I think it's because rather than decreasing its setting it to a certain value? Rather than jumping it just snaps to whatever value that constant is relative to its position. I'm so confused with this.
Make sure that if you're using two bytes for Y, that you're using the higher of the two bytes for your world (and screen, for a single screen game) Y coordinate. Make sure when you set the velocity to a negative value that you only do it once, at the start of a jump. This requires that you detect an off-to-on transition in the controller, and if the button continues to be pressed you'll only see on-to-on transitions, and you won't reset the velocity again. Finally make sure you're adding a constant positive acceleration to the velocity on each frame, as well as adding velocity to your Y coordinate each frame. Again, using only the high byte of the Y for your actual world/screen coordinate (just pull out y_coordinate+1 when deciding where to draw the sprite). Not sure if that helps, maybe post your asm file again to inspect. It's probably something small.
It might even be worthwhile to practice sub pixel movement in isolation before going all the way to a jump (like, no other logic, just accelerate, or decelerate, moving in one direction on X or Y perhaps). Though you did say you've got smoother movement, now. If the jump is then too fast, as you describe, the only guess I have is that when you set the initial velocity it is much too high and maybe you're setting the high byte of the velocity when you want to be setting the low byte to some negative value, and the high byte to $ff (you need to sign extend...). Note in my original example, lda #>START_JUMP should be setting the hi byte to $ff (because START_JUMP is negative, the assembler should sign extend for you when you use > ). you'd use lda #high and lda #low instead of #> and #< in nesasm.
Also important: if positions are 16.8 bits, and speeds are 8.8 bits, you have to sign-extend the speeds when adding them to the positions. If the speed is positive, you have to add $00 to the high byte of the position, otherwise you have to add $ff. I normally handle this by branching based on the N flag after loading the speed for adding:
Code:
clc
lda SpeedFraction
adc PositionFraction
sta PositionFraction
lda Speed
bmi AddNegativeSpeed
AddPositiveSpeed:
adc Position+0
sta Position+0
lda #$00
beq Finish
AddNegativeSpeed:
adc Position+0
sta Position+0
lda #$ff
Finish:
adc Position+1
sta Position+1
I'm going to set down and study this and like you mentioned try it separately from everything else. If that doesn't work I'll go read up and try to see if I can do it in a higher level language for practice, then come back to the NES with it. Thank you both for being so helpful.