Collision data: 8 or 16 bit?
Moderator: Moderators
Re: Collision data: 8 or 16 bit?
delete post
Last edited by sdm on Tue Jan 19, 2016 3:35 am, edited 1 time in total.
Re: Collision data: 8 or 16 bit?
I'm confused because for demonstration let's say I am putting it in RAM. In that example you're defining this here:
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?
Code: Select all
map_data: .rs 32 * 30- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Collision data: 8 or 16 bit?
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.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: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?Code: Select all
map_data: .rs 32 * 30
Re: Collision data: 8 or 16 bit?
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.
Attached is the code in advance.
- Attachments
-
- main.asm
- (3.86 KiB) Downloaded 71 times
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Collision data: 8 or 16 bit?
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.
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.
Code: Select all
;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
*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.
Re: Collision data: 8 or 16 bit?
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.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Collision data: 8 or 16 bit?
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!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.
Re: Collision data: 8 or 16 bit?
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.
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.
Re: Collision data: 8 or 16 bit?
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.
Thanks, zkip.
- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Collision data: 8 or 16 bit?
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.
*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.
Re: Collision data: 8 or 16 bit?
I suppose I do need acceleration to simulate a jump. I tried this:
and set that from the button code:
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.
Code: Select all
procesesjump:
lda playerjmpflag
beq .r
lda jumptimer
sec
sbc player-yspeed
sta player-yspeed
dec jumptimer
.r
rtsCode: Select all
bwaspressed:
lda #$10
sta jumptimer- GradualGames
- Posts: 1106
- Joined: Sun Nov 09, 2008 9:18 pm
- Location: Pennsylvania, USA
- Contact:
Re: Collision data: 8 or 16 bit?
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: Select all
;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.
Re: Collision data: 8 or 16 bit?
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?
Re: Collision data: 8 or 16 bit?
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.
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.
Re: Collision data: 8 or 16 bit?
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.
You could try the SMB3 approach: 16 bit integers with 4 bits of subpixel, 8 bits of pixel, and 4 bits of screen.