|
Post by DarkKobold on Oct 24, 2019 23:23:28 GMT
So, hitboxes are important. Like way important. Arkhan and I had a discussion like 4 months ago, that lead to a real nice change in how I was handling my own hitbox code. Before, I was writing awful if statements with multiple accesses to the same array, which of course HuC hates. I figured I'd share this for posterity, because every game needs hit boxes.
Globals - int ax1,ax2,ay1,ay2,bx1,bx2,by1,by2; char hitboxreturn;
hitbox() { hitboxreturn=1; if (ax1>bx2) {hitboxreturn=0; return;} if (ax2<bx1) {hitboxreturn=0; return;} if (ay1>by2) {hitboxreturn=0; return;} if (ay2<by1) {hitboxreturn=0; return;} } ax1 is left side of one hitbox, ax2 is the right, ay1 is the top, ay2 is the bottom. Same for bx1,bx2,by1,by2.
There are multiple benefits to the way this is written - if a single violation is hit early, it exits the code. Additionally, if you need to make multiple checks to the same hit box, you can cycle the a's or b's, without re-referencing the other.
Here's the sort of garbage I used to write. The new method is way better.
if (enemystate[i]<60) //NEED TO SORT INVUNERABLE { if (enemyz[i]<16) //enemy on ground { if ((catmapy+2>enemyy[i]) && (catmapy-8<enemyy[i])) { if (((catx-18)<(enemyx[i]+32)) && ((catx+50)>enemyx[i])) {
|
|
|
Post by Arkhan on Oct 25, 2019 1:14:27 GMT
as a boner inducing exercise for yourself, you should convert that to assembly.
|
|
|
Post by DarkKobold on Oct 25, 2019 1:55:02 GMT
as a boner inducing exercise for yourself, you should convert that to assembly. I've been wondering about that - it seems like the ASM version that HuC would come up with would probably be fairly optimal. If I were still doing array-based references, it might be faster.
.proc _hitbox __ldwi 1 stx _hitboxreturn __ldw _ax1 __stw <__temp __ldw _bx2 jsr gtzp __lbeqn LL4837 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4837:
__ldw _ax2 __stw <__temp __ldw _bx1 jsr ltzp __lbeqn LL4838 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4838:
__ldw _ay1 __stw <__temp __ldw _by2 jsr gtzp __lbeqn LL4839 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4839:
__ldw _ay2 __stw <__temp __ldw _by1 jsr ltzp __lbeqn LL4840 __ldwi 0 stx _hitboxreturn __lbran LL4836 LL4840: Seems fairly optimal to me?
|
|
Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Oct 25, 2019 2:15:17 GMT
Can you read asmsmsms now?
This is my AABB code for BrickBreaker. Keep in mind it was written in like a day or so but it works and it's fairly easy to read since it doesn't have macros up the ass or clever optimizations.
;Same as overlap test but only the first box of each object is tested. ;Preserves X, Y. Outputs A. ;Make sure objects' metasprites are VALID! Overlap_Test_1Box: TXA STA <Obj1Id TYA STA <Obj2Id CMP <Obj1Id BNE .cont JMP .noOverlap ;If both objects are the same, report no collision. .cont ;Gets pointers to collision data LDA OBJ_METASPRITE, x ASL A ASL A STA <Obj1Box LDA OBJ_METASPRITE, y ASL A ASL A STA <Obj2Box ;Must pass all 4 tests to be overlapping. .Test1: ;Obj2.y2 > Obj1.y1 CLC LDY <Obj1Box LDX <Obj1Id LDA MS_Collision_Table + 2, y ADC OBJ_YPOS, x STA <TempPos CLC LDY <Obj2Box LDX <Obj2Id LDA MS_Collision_Table + 3, y ADC OBJ_YPOS, x CMP <TempPos BCS .Test2 ;Test true, move to next one. JMP .noOverlap .Test2: ;Obj1.y2 > Obj2.y1 CLC LDY <Obj2Box LDX <Obj2Id LDA MS_Collision_Table + 2, y ADC OBJ_YPOS, x STA <TempPos CLC LDY <Obj1Box LDX <Obj1Id LDA MS_Collision_Table + 3, y ADC OBJ_YPOS, x CMP <TempPos BCS .Test3 ;Test true, move to next one. JMP .noOverlap .Test3: ;Obj2.x2 > Obj1.x1 CLC LDY <Obj1Box LDX <Obj1Id LDA MS_Collision_Table, y ADC OBJ_XPOS, x STA <TempPos CLC LDY <Obj2Box LDX <Obj2Id LDA MS_Collision_Table + 1, y ADC OBJ_XPOS, x CMP <TempPos BCS .Test4 ;Test true, move to next one. JMP .noOverlap .Test4: ;Obj1.x2 > Obj2.x1 CLC LDY <Obj2Box LDX <Obj2Id LDA MS_Collision_Table, y ADC OBJ_XPOS, x STA <TempPos CLC LDY <Obj1Box LDX <Obj1Id LDA MS_Collision_Table + 1, y ADC OBJ_XPOS, x CMP <TempPos BCS .Overlap ;All tests false, box1 overlaps with box2 .noOverlap: LDA #OVERLAP_FALSE LDX <Obj1Id LDY <Obj2Id RTS .Overlap: LDA #OVERLAP_TRUE LDX <Obj1Id LDY <Obj2Id RTS
|
|
|
Post by Arkhan on Oct 25, 2019 2:43:11 GMT
I believe all the 16 bittery macro stuff in the HuC'd one is going to be inherently slower than doing something like Pumcho over here.
Also, I found in the HuCDoc.html or whatever that comes with HuC, it has a blurb about inline asm. That's probably where I read about it 10 years ago to do stuff.
|
|
|
Post by theoldman on Oct 25, 2019 4:56:52 GMT
DarkKobold : "I've been wondering about that - it seems like the ASM version that HuC would come up with would probably be fairly optimal. If I were still doing array-based references, it might be faster."
Arkhan: "I believe all the 16 bittery macro stuff in the HuC'd one is going to be inherently slower than doing something like Pumcho over here."
I'm not an expert in asm, by any means, but some of what HuC generates is ... sub-optimal, at best. I understand -why- that is, because it's pretty stright-forward CS-200 code generation.
However, as arkhan says, the __ macros (snd others) just make it harder to understand what's going on. Something that looks simple and quick can be slower than you think.
For example, in DarkKobolds hit box code, every section contains the lines
" __ldwi 0 stx _hitboxreturn "
Optimal? Hardly...
__ldwi (iirc) is "load word immediate". Why ? We go on to only save X, so why bother A at all? Even more importantly, since we then store the low byte, why load a 0 just to store it ?
ideally, those 2 lines should be replaceable by a simple "stz _hitboxreturn".
And don't get me started on the stupidity of moving values to <_temp just so you can do a zero-page compare. I'd swear there's another macro that does just that, on the actual variables....And if not, how hard is it to do the correct compare? Especially with examples all over in the HuC libraries themselves?
Now, HuC is a good place to -start- with assembler functions. But, if you are using HuC for assembler, take a look at what gets generated; many times it caan be improved on without much effort. And it's actually a good way to get a working knowledge of assembler.
|
|
|
Post by turboxray on Oct 25, 2019 8:06:20 GMT
For example, in DarkKobolds hit box code, every section contains the lines " __ldwi 0 stx _hitboxreturn " Optimal? Hardly... __ldwi (iirc) is "load word immediate". Why ? We go on to only save X, so why bother A at all? Even more importantly, since we then store the low byte, why load a 0 just to store it ? ideally, those 2 lines should be replaceable by a simple "stz _hitboxreturn". Because HuC was never meant to be more than a novelty.. to attract people into PCE scene. Then graduate into ASM. I believe dshadoff added an optimization switch that optimizes some of the 16bit handling macros to 8bit (on the appropriate type). Yeah some of the code is sub-optimal, but hey inline-asm haha. Does any of the knew HuC builds support static inside declarations inside functions? Would be a nice way to get globals type speed, but a little bit of scoping (for naming variables).
|
|
touko
Punkic Cyborg
Posts: 106
|
Post by touko on Oct 25, 2019 8:17:05 GMT
My fastest collision routine takes 80 cycles if collision . The best way to go with boxes is to do 1 vs many,you precalc the X and Y boxes for your first sprite once .
|
|
|
Post by turboxray on Oct 25, 2019 8:17:25 GMT
as a boner inducing exercise for yourself, you should convert that to assembly. I've been wondering about that - it seems like the ASM version that HuC would come up with would probably be fairly optimal. If I were still doing array-based references, it might be faster.
.proc _hitbox __ldwi 1 stx _hitboxreturn __ldw _ax1 __stw <__temp __ldw _bx2 jsr gtzp __lbeqn LL4837 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4837:
__ldw _ax2 __stw <__temp __ldw _bx1 jsr ltzp __lbeqn LL4838 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4838:
__ldw _ay1 __stw <__temp __ldw _by2 jsr gtzp __lbeqn LL4839 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4839:
__ldw _ay2 __stw <__temp __ldw _by1 jsr ltzp __lbeqn LL4840 __ldwi 0 stx _hitboxreturn __lbran LL4836 LL4840: Seems fairly optimal to me?
Ehh.. not too optimal haha. __ldw _ax2 __stw <__temp __ldw _bx1 jsr ltzp __lbeqn LL4838 __ldwi 0 stx _hitboxreturn __lbra LL4836 LL4838: The stw <__temp and jsr are unnecessary. If it was pure asm, and you only needed to know of collision happened or not. Probably have something like rely on the compare to set the carry flag and simple return. I'm surprised by the ldwi and stx not simply optimized as stz _hitboxreturn though. Didn't Uli add some optimizations to HuC?
|
|
|
Post by Arkhan on Oct 25, 2019 15:04:30 GMT
The best way to go with boxes is to do 1 vs many,you precalc the X and Y boxes for your first sprite once . That is what I do, and what I suggested DK do and is kind of what is going on there. It makes life much easier.
|
|
|
Post by dshadoff on Oct 25, 2019 16:17:27 GMT
Does any of the knew HuC builds support static inside declarations inside functions? Would be a nice way to get globals type speed, but a little bit of scoping (for naming variables). Yes, I was doing this last week in HuC v3.21
|
|
|
Post by DarkKobold on Oct 25, 2019 19:46:47 GMT
I think I would struggle to rewrite this in ASM, simply given that all my globals are 2 bytes, and I'm not familiar with how to do 16bit math on an 8bit processor. If I knew how to force the ax,bx, etc to zero page, maybe it'd be worth it?
Also, I'm not sure that its necessary. The Beat'em Up in our game is now lag-free, thanks to ASM-based Zsorting. The 5ish CPU cycles lost to ldwi don't seem that expensive.
|
|
touko
Punkic Cyborg
Posts: 106
|
Post by touko on Oct 25, 2019 21:19:53 GMT
I think I would struggle to rewrite this in ASM, simply given that all my globals are 2 bytes, and I'm not familiar with how to do 16bit math on an 8bit processor. If I knew how to force the ax,bx, etc to zero page, maybe it'd be worth it? You have all you need here : codebase64.org/doku.php?id=base:6502_6510_mathsYou can even use the pceas's macros(addw , subw,etc ...) if you want to do it easily .
|
|
|
Post by DarkKobold on Nov 18, 2019 20:28:35 GMT
On this topic, does anyone know a good algorithm for diagonal hitboxes?
|
|
|
Post by turboxray on Nov 18, 2019 20:44:09 GMT
On this topic, does anyone know a good algorithm for diagonal hitboxes? Diagonal hit boxes? You mean diagonal parts for background collision?
|
|