 |
|
 |
|
| Object clipping... doesn't have to be 16x16? |
|
Forum Index - SMW Hacking - General SMW Hacking Help - SMW Data Repository - Object clipping... doesn't have to be 16x16? |
|
Pages: 1  |
|
|
|
| Posted on 2010-05-27 11:28:17 PM |
Link | Quote |
|
While trying to find which object clipping would do what, I wrote a simple sprite that would move back and forth, bounce off walls, change object clippings when the user pressed R, jump when the user pressed L, and display the current clipping on the status bar. I tested it in order to find out information about the object clippings themselves, and much to my surprise, when I got to object clipping E, the sprite appeared to have an interactivity zone 32 pixels wide! Just to make sure it wasn't just a fluke or a frame-flipping thing, I checked the table at $0190BA, (SpriteObjClippingX: in all.log) and lo and behold, at table offset $1C, ($0E * 2) the value was 1F!
This opens up gigantic possibilities if it coded properly. We obviously can't change any of the existing clippings, so what we could do is to make a local copy of whatever routine reads from that table, and hardcode it to read certain values, thus giving each individual sprite custom, flexible object interaction!
...then again, there's always the chance that I'm wrong, but then again, that's always a possibility.
Link to sprite ASM
Link to sprite CFG
|
|
| Posted on 2010-05-28 02:00:09 AM |
Link | Quote |
|
|
Wow. I don't have time to test this right now, but if this is right, this could be awesome. Neato, no more thwomps that disregard anything on their left hand side.
|
| Last edited on 2010-05-28 02:00:25 AM by HuFlungDu. |
|
| Posted on 2010-05-28 06:15:07 AM |
Link | Quote |
|
That's nice if it really works - haven't had the time to test it either -, but I was pretty positive that this table wasn't for clipping width, but relative X position. If it was for width, then a lot of values would not make the clipping width exactly 16x16, as you can see almost none of the values are $0F or $10.
CodeSpriteObjClippingX: .db $0E,$02,$08,$08,$0E,$02,$07,$07
.db $07,$07,$07,$07,$0E,$02,$08,$08
.db $10,$00,$08,$08,$0D,$02,$08,$08
.db $07,$00,$04,$04,$1F,$01,$10,$10
.db $0F,$00,$08,$08,$10,$00,$08,$08
.db $0D,$02,$08,$08,$0E,$02,$08,$08
.db $0D,$02,$08,$08,$10,$00,$08,$08
.db $1F,$00,$10,$10,$08
I'm skeptic about this. But, if it works, nice job.
|
|
| Posted on 2010-05-28 09:53:37 AM |
Link | Quote |
|
Okay, a couple things now: first, I found that the 1F does not correspond with clipping E, but in fact with clipping 7. There are enough values in the table for 0E clippings, leaving the Fth unfinished and buggy.
So anyway, for a simple proof of concept, I changed the first 1F to a 30, and yes, on clipping 7, the sprite appeared to have a three-tile wide range of clipping: starting at the sprite, and ending 48 pixels to the right.
If this works out, then each dimension has four values... that's enough to do a lot of stuff, not just offset and length.
For clipping 0, the table would look like this:
X: $0E,$02,$08,$08
Y: $08,$08,$10,$02
Clipping 1 holds the sprite one tile off the ground:
X: $0E,$02,$07,$07
Y: $12,$12,$20,$02
In another experiment, I changed the 20 in the Y-values of clipping 1 to an 18, causing the sprite to bounce up and down between $20 pixels and what appeared to be a little greater than $18 pixels... almost as though there was a conflict between two of the values in the clipping.
I ran one last test, in which I reverted the 18 to a 20 in clipping 1, and changed the first twelve to a 20. The sprite elevated 16 pixels off the ground, bounced off the left wall... and passed through the right wall? This makes me think that sprite direction has something to do with this... maybe the four values are just two sets of two values, indexed between the two for each direction?
I'm still puzzled on this, so I'll do a bit of examination on the routine that reads those values to figure out exactly what's going on here.
|
|
| Posted on 2010-05-28 10:37:20 AM |
Link | Quote |
|
If you're right, than this could be great. And I don't believe that it would be impossible to expand the clipping table. If clipping F is unused, then all we have to do is hack the routine that reads the values and check to see if someone set a particular sprite's object clipping to F, and if so, use a completely different sprite table (such as $7FAB64,x) to determine its object clipping. We could do the same with sprite clipping, since I think sprite clipping settings 3C-3F are unused.
Edit: Yep.
CODE_019457: 18 CLC
CODE_019458: 79 F7 90 ADC.W SpriteObjClippingY,Y
CODE_01945B: 85 0C STA $0C
CODE_01946E: 18 CLC
CODE_01946F: 79 BA 90 ADC.W SpriteObjClippingX,Y
CODE_019472: 85 0A STA $0A
CODE_0194C1: 18 CLC
CODE_0194C2: 79 F7 90 ADC.W SpriteObjClippingY,Y
CODE_0194C5: 85 0C STA $0C
CODE_0194DF: 18 CLC
CODE_0194E0: 79 BA 90 ADC.W SpriteObjClippingX,Y
CODE_0194E3: 85 0A STA $0A
Those four sections of code seem to be the only place where the object clipping values are referenced. Each one even has four neat little bytes to hijack. It would be simple to just put a JML or JSL in each of those four locations and return a value to store in $0C or $0A depending on what the clipping was set to.
The sprite clipping tables, by the way, are at $03B56C:
SprClippingDispX: .db $02,$02,$10,$14,$00,$00,$01,$08
.db $F8,$FE,$03,$06,$01,$00,$06,$02
.db $00,$E8,$FC,$FC,$04,$00,$FC,$02
.db $02,$02,$02,$02,$00,$02,$E0,$F0
.db $FC,$FC,$00,$F8,$F4,$F2,$00,$FC
.db $F2,$F0,$02,$00,$F8,$04,$02,$02
.db $08,$00,$00,$00,$FC,$03,$08,$00
.db $08,$04,$F8,$00
SprClippingWidth: .db $0C,$0C,$10,$08,$30,$50,$0E,$28
.db $20,$14,$01,$03,$0D,$0F,$14,$24
.db $0F,$40,$08,$08,$18,$0F,$18,$0C
.db $0C,$0C,$0C,$0C,$0A,$1C,$30,$30
.db $08,$08,$10,$20,$38,$3C,$20,$18
.db $1C,$20,$0C,$10,$10,$08,$1C,$1C
.db $10,$30,$30,$40,$08,$12,$34,$0F
.db $20,$08,$20,$10
SprClippingDispY: .db $03,$03,$FE,$08,$FE,$FE,$02,$08
.db $FE,$08,$07,$06,$FE,$FC,$06,$FE
.db $FE,$E8,$10,$10,$02,$FE,$F4,$08
.db $13,$23,$33,$43,$0A,$FD,$F8,$FC
.db $E8,$10,$00,$E8,$20,$04,$58,$FC
.db $E8,$FC,$F8,$02,$F8,$04,$FE,$FE
.db $F2,$FE,$FE,$FE,$FC,$00,$08,$F8
.db $10,$03,$10,$00
SprClippingHeight: .db $0A,$15,$12,$08,$0E,$0E,$18,$30
.db $10,$1E,$02,$03,$16,$10,$14,$12
.db $20,$40,$34,$74,$0C,$0E,$18,$45
.db $3A,$2A,$1A,$0A,$30,$1B,$20,$12
.db $18,$18,$10,$20,$38,$14,$08,$18
.db $28,$1B,$13,$4C,$10,$04,$22,$20
.db $1C,$12,$12,$12,$08,$20,$2E,$14
.db $28,$0A,$10,$0D
And the routines that reference them...
CODE_03B6A8: 64 0F STZ $0F ; \
CODE_03B6AA: BF 6C B5 03 LDA.L SprClippingDispX,X ; | Load low byte of X displacement
CODE_03B6AE: 10 02 BPL CODE_03B6B2 ; |
CODE_03B6BD: 85 0A STA $0A ; / $0A = (Sprite X position + displacement) High byte
CODE_03B6BF: BF A8 B5 03 LDA.L SprClippingWidth,X ; \ $06 = Clipping width
CODE_03B6C3: 85 06 STA $06
CODE_03B6C5: 64 0F STZ $0F ; \
CODE_03B6C7: BF E4 B5 03 LDA.L SprClippingDispY,X ; | Load low byte of Y displacement
CODE_03B6CB: 10 02 BPL CODE_03B6CF ; |
CODE_03B6DA: 85 0B STA $0B ; / $0B = (Sprite Y position + displacement) High byte
CODE_03B6DC: BF 20 B6 03 LDA.L SprClippingHeight,X ; \ $07 = Clipping height
CODE_03B6E0: 85 07 STA $07
CODE_03B6EE: 64 0F STZ $0F ; \
CODE_03B6F0: BF 6C B5 03 LDA.L SprClippingDispX,X ; | Load low byte of X displacement
CODE_03B6F4: 10 02 BPL CODE_03B6F8 ; |
CODE_03B703: 85 08 STA $08 ; / $08 = (Sprite X position + displacement) High byte
CODE_03B705: BF A8 B5 03 LDA.L SprClippingWidth,X ; \ $02 = Clipping width
CODE_03B709: 85 02 STA $02 ; /
CODE_03B70B: 64 0F STZ $0F ; \
CODE_03B70D: BF E4 B5 03 LDA.L SprClippingDispY,X ; | Load low byte of Y displacement
CODE_03B711: 10 02 BPL CODE_03B715 ; |
CODE_03B720: 85 09 STA $09 ; / $09 = (Sprite Y position + displacement) High byte
CODE_03B722: BF 20 B6 03 LDA.L SprClippingHeight,X ; \ $03 = Clipping height
CODE_03B726: 85 03 STA $03 ; /
|
| Last edited on 2010-05-28 10:50:01 AM by imamelia. |
|
| Posted on 2010-05-28 11:29:47 AM |
Link | Quote |
|
Hm. You're right. I just changed all values (well, one per four since it's 4 values for each clipping value) in that clipping table to use value $3F, and whaddayaknow... the X clipping is 4 tiles wide for every sprite.
Nice find. And me always thinking clipping X was just for the relative position...
|
|
| Posted on 2010-05-28 04:24:34 PM |
Link | Quote |
|
|
I always figured for something like a 32x32 sprite you could just preserve the sprites X/Ypos a few times and JSL to the object routine 4 times.
|
|
| Posted on 2010-05-28 05:38:40 PM |
Link | Quote |
|
Okay, new stuff.
First off, take a look at this: for every single clipping, in the X-tables, the second two values are the same, and for the Y-clipping, the first two values are the same. This mostly reaffirms my theory about direction being a key part of the clipping tables. Those particular values are the same for both directions.
In addition, I have some code to back me up. The only routine that looks at those tables is $019441, (there is $0194BF, but that's just a clone for vertical levels) which starts off by taking Y and using it as the low two bits of the index to the tables. The only two places that that is called are at $019291 and $0192D0, both of which set values to Y based on sprite direction, calculated by the high bit of $B6,x.
Anyway, I'm still puzzled with what all the different values could mean. The call from $019291 will read the first two values for each clipping, and the call from $0192D0 will read the second two values, as the setting to Y is preceded with an LDY #$02, followed by an optional INY.
|
|
| Posted on 2010-06-05 03:45:49 AM |
Link | Quote |
|
forgot to reply to this..
Originally posted by Noobish NoobsicleAnyway, I'm still puzzled with what all the different values could mean.
The clip tables are just displacements for the sprite X and Y positions. Y index is set to 00-03 based on one of four directions and that is used for the X/Y clip table index (plus the object clipping tweaker table ofcourse). It then builds a pointer to map16 RAM and reads the block at that location. The routines you mentioned do all that math required so what part in particular is puzzling? I have all this documented but won't bother making it presentable if this is already figured out.
It's easy to make custom clip values but very wide clippings or very tall clippings will have 'holes' in them because it only checks one block for a given direction, not the entire span of the clipping.
|
|
| Posted on 2010-07-08 11:49:24 AM |
Link | Quote |
|
It looks to me like $019288 and $0192C9 are the two different routines that set Y. $019288 checks (bit 7 of) the sprite X speed and uses Y = 00/01, and $0192C9 checks (bit 7 of) the Y speed and uses Y = 02/03. So it isn't the direction of the sprite that matters (most sprites don't use vertical direction anyway), but the speed. At least, it isn't the direction as far as $157C,x and $151C,x go.
Originally posted by smkdanI have all this documented but won't bother making it presentable if this is already figured out.
Why not present it anyway? It can't hurt.
Originally posted by smkdanvery wide clippings or very tall clippings will have 'holes' in them because it only checks one block for a given direction, not the entire span of the clipping.
What exactly do you mean by "holes"? You mean it could be one block shorter in either direction than was intended (like, the sprite bounces off one wall normally, but seemingly goes 15 pixels into the other wall before changing direction)? And just how wide or tall is too wide or tall to work properly?
Sprite clipping is so much simpler...it just uses four straightforward tables for clipping X displacement, Y displacement, width, and height. I'm just glad that most sprites that interact with objects aren't an odd size, and object interaction usually doesn't have to be as precise anyway.
|
|
| Posted on 2010-07-12 04:31:01 AM |
Link | Quote |
|
I have some code to back me up. The only routine that looks at those tables is $019441, (there is $0194BF, but that's just a clone for vertical levels) which starts off by taking Y and using it as the low two bits of the index to the tables. The only two places that that is called are at $019291 and $0192D0, both of which set values to Y based on sprite direction, calculated by the high bit of $B6,x.
________________________________________________________________
Ben 10 Games
|
|
| Posted on 2010-09-06 02:46:04 PM |
Link | Quote |
|
I think this thread needs more attention.
Okay, so...$019288 and $0192C9. As I said before, $019288 checks the sign of the sprite X speed, and $0192C9 checks the sign of the sprite Y speed. $019288, however, has a second entry point at $01928E:
CodeCODE_019272: BD 0F 19 LDA.W RAM_Tweaker190F,X ; \ Branch if "Don't get stuck in walls" is not set
CODE_019275: 10 11 BPL CODE_019288 ; /
CODE_019277: B5 B6 LDA RAM_SpriteSpeedX,X ; \ Branch if sprite has X speed...
CODE_019279: 1D AC 15 ORA.W $15AC,X ; | ...or sprite is turning
CODE_01927C: D0 0A BNE CODE_019288 ; /
CODE_01927E: A5 13 LDA RAM_FrameCounter
CODE_019280: 20 8E 92 JSR.W CODE_01928E
Return019283: 60 RTS ; Return
DATA_019284: .db $FC
DATA_019285: .db $04,$FF,$00
CODE_019288: B5 B6 LDA RAM_SpriteSpeedX,X
CODE_01928A: F0 34 BEQ Return0192C0
CODE_01928C: 0A ASL
CODE_01928D: 2A ROL
CODE_01928E: 29 01 AND.B #$01
CODE_019290: A8 TAY
If 1) the sprite's X speed is not zero, 2) the "Don't get stuck in walls" Tweaker bit is set, or 3) $15AC,x (usually used as a turn timer) is nonzero, the routine is run normally. If none of those things are true, the frame counter is used as an index, and the routine starts at the second entry point.
The million-dollar question, though, is: Why does object clipping require 8 table values per clipping when sprite clipping requires only 4 (X displacement, Y displacement, width, height)? Was there actually a purpose for using the different values depending on the sign of the sprite speed? And what exactly does each value do anyway? Is it that they are all offsets and there is no width or height involved at all, but the offsets determine where the 16x16 interaction field should be depending on which way the sprite is going? That would mean that there are 4 tiles that interact (they can overlap) and form the corners of a square, which would be the full object interaction field. But if that is the case, I see what smkdan means about there being holes in the field...any object clipping field larger than 32x32 would have that problem, and it would get more noticeable the bigger the clipping got. Like, if the clipping size were 80x80, or 5 by 5 tiles, only 4 of the 16 tiles around the perimeter of the clipping field—the four corner tiles—would actually interact with objects.
Come to think of it, SMW's object interaction routine can't be all that efficient anyway. It's, like, the longest and most time-intensive of any sprite subroutine, copy-pasted or JSLed to. I doubt it would be easy to make a better one, though....
|
|
|
Pages: 1  |
|
|
|
|
Forum Index - SMW Hacking - General SMW Hacking Help - SMW Data Repository - Object clipping... doesn't have to be 16x16? |
|
|
 |
|
 |
The purpose of this site is not to distribute copyrighted material, but to honor one of our favourite games.
Copyright © 2005 - 2013 - SMW Central Legal Information - Link To UsTotal queries: 29
|
|
|
|