News:

11 March 2016 - Forum Rules

Main Menu

Sprite Disappearing Issue

Started by justin3009, January 07, 2017, 08:25:51 PM

Previous topic - Next topic

justin3009

Going back to test the bigger Peach sprite in SMB2 and I noticed a rather fun oddity.  When you're on the edge of the screen apparently chunks of her sprites disappear because they're hitting, I guess, an odd section of the screen causing it to not loop properly or something.  It has to do with my code, just not entirely sure 'why' it's doing it.

- Here's the image to show what's happening.

$94/E1C8 A7 00       LDA [$00]  [$BE:9109]   A:0002 X:0098 Y:0A46 P:envMxdizc ;Load X coordinate of Sprite Assembly
$94/E1CA 09 00       ORA #$00                A:0008 X:0098 Y:0A46 P:envMxdizc
$94/E1CC 85 0E       STA $0E    [$00:000E]   A:0008 X:0098 Y:0A46 P:envMxdizc ;Store temp X coordinate value to 7E:000E
$94/E1CE A5 9D       LDA $9D    [$00:009D]   A:0008 X:0098 Y:0A46 P:envMxdizc ;Load current direction of PC
$94/E1D0 D0 07       BNE $07    [$E1D9]      A:0000 X:0098 Y:0A46 P:envMxdiZc ;If > 0, break to $94/E1D9
$94/E1D2 A5 0E       LDA $0E    [$00:000E]   A:0000 X:0098 Y:0A46 P:envMxdiZc ;Load temp X coordinate value from 7E:000E
$94/E1D4 38          SEC                     A:0008 X:0098 Y:0A46 P:envMxdizc
$94/E1D5 49 FF       EOR #$FF                A:0008 X:0098 Y:0A46 P:envMxdizC ;EOR FF
$94/E1D7 80 02       BRA $02    [$E1DB]      A:00F7 X:0098 Y:0A46 P:eNvMxdizC
$94/E1DB 18          CLC                     A:00F7 X:0098 Y:0A46 P:eNvMxdizC ;Set carry flag
$94/E1DC 6D 28 04    ADC $0428  [$91:0428]   A:00F7 X:0098 Y:0A46 P:eNvMxdizc ;Add PC's screen X coordinates
$94/E1DF 9F 00 08 7E STA $7E0800,x[$7E:0898] A:00FE X:0098 Y:0A46 P:eNvMxdizc ;Store to OAM


It seems odd that they just completely poof off screen.  There's no other code that messes with any of the data either as this is all from scratch.  So what's here is exactly what's here.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

Zeikar

she needs to be shorter than the door?

Disch

My guess:

Your sprite is running off the screen to the left (its X coordinate is less than 0).  Since in your code, you seem to be only treating the X coordinate as an 8-bit value, that means you're wrapping around to the right side of the screen.  For example, if the X coordinate is -1, it'll actually be drawn at $FF (way on the right side of the screen)


If this is the case, the problem can be solved by treating X coord as a 9-bit signed value as it's intended to be.  The 9th bit is in the secondary "high" OAM table and is much, MUCH goofier to edit.

From anomie's regs.txt:

The record format for the low table is 4 bytes:
  byte OBJ*4+0: xxxxxxxx
  byte OBJ*4+1: yyyyyyyy
  byte OBJ*4+2: cccccccc
  byte OBJ*4+3: vhoopppN

The record format for the high table is 2 bits:
  bit 0/2/4/6 of byte OBJ/4: X
  bit 1/3/5/7 of byte OBJ/4: s

The values are:
  Xxxxxxxxx = X position of the sprite. Basically, consider this signed.

justin3009

Quote from: Disch on January 07, 2017, 09:11:50 PM
If this is the case, the problem can be solved by treating X coord as a 9-bit signed value as it's intended to be.  The 9th bit is in the secondary "high" OAM table and is much, MUCH goofier to edit.

From anomie's regs.txt:

The record format for the low table is 4 bytes:
  byte OBJ*4+0: xxxxxxxx
  byte OBJ*4+1: yyyyyyyy
  byte OBJ*4+2: cccccccc
  byte OBJ*4+3: vhoopppN

The record format for the high table is 2 bits:
  bit 0/2/4/6 of byte OBJ/4: X
  bit 1/3/5/7 of byte OBJ/4: s

The values are:
  Xxxxxxxxx = X position of the sprite. Basically, consider this signed.


You're guess is absolutely right for sure, that's what I assumed it was as well.

I hate to say it but that whole quoted section goes right over my head.  I don't understand a single bit of it  :-X

Edit: Also, it turns out that even the original game didn't plan for this.  I think they had a specific set limit for ALL sprites on screen to break once it hits 00.  So this might be a bit of a doozy to fix.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

Disch

So there's 2 different ways of thinking of OAM.  It's either 1 big table of 544 bytes.... or it's 2 separate tables (one 512 bytes and the other 32 bytes).  For our purposes, let look at it as if it were 2 different tables.

I'm sure you're familiar with the 512 table.  That's the one you're editing... it's the one where each sprite is assigned 4 bytes:
1) The X position
2) The Y position
3) The tile to use
4) Various flags, palette assignment

There are 128 sprites.  Each has 4 bytes... hence 4*128 = 512 bytes total.


The 32 table is weirder.  Each sprite also has an entry in this table, but they only get two bits.  Meaning each byte in the table is actually the entries for 4 separate sprites.  One bit selects the size of the sprite, the other is the high bit of the X position.



The problem here is that the X coordinate in the 512 table is only 8 bits wide, which only gives you an effective range of [0..255].  However, we need a wider range than that if the sprite is going to move cleanly off the left side of the screen, so they gave it a 9th bit in the 32 table, and making the full 9-bit value signed... changing the range to [-256..255].

So your goal, should you choose to accept it, is to update that 9th bit of the X position along with the other 8 bits.

If $7E0800 is the start of your 512 table... then that probably means $780A00 is the start of your 32 table.

You'd find the 9th bit like so:


Sprite #    |  X pos in 512 table  |  Byte in 32 table  |  Bit in that byte
------------+----------------------+--------------------+----------------------
0           |    $7E0800           |    $7E0A00         |  bit 0 -> ($01)
1           |    $7E0804           |    $7E0A00         |  bit 2 -> ($04)
2           |    $7E0808           |    $7E0A00         |  bit 4 -> ($10)
3           |    $7E080C           |    $7E0A00         |  bit 6 -> ($40)
4           |    $7E0810           |    $7E0A01         |  bit 0 -> ($01)
5           |    $7E0814           |    $7E0A01         |  bit 2 -> ($04)
6           |    $7E0818           |    $7E0A01         |  bit 4 -> ($10)
7           |    $7E081C           |    $7E0A01         |  bit 6 -> ($40)
...



So you'd need to find that 9th bit in the 32 table... and set it according to the C flag (9th bit of your addition) after you add the TSA value to the player position.

justin3009

#5
Oh so THAT'S what that table is.  I've been noting that down but it appeared like it was just the sprite size.  I've been using that table A LOT though so that definitely makes sense.. though I'm pretty sure it extends way beyond 32 bytes at the moment.  I'll see what I can do about fixing this.  Just means I'll have to insert this specific data into the sprite assembly storing area which isn't a big deal actually, that's probably a good idea in the long run.

Edit: Working on a way to get it to update now.  Trying to figure out exactly 'how' it'd be done.  I assume if it overflows or underflows is when it'd set the value.  I do have it working on the idle pose but once I start moving, weirdly half the sprite just disappears again.  Might take a bit.  Not sure if it's absolutely right but it looks like setting a value of '03' instead of '02' fixes it when it hits the edge of the screen though.  If I do get it to work though, once you move off of a 'single' screen it starts bugging up again.  This could be a super annoying problem to fix.
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'

assassin

what are you trying to accomplish with 94/E1CA and 94/E1D4?  pretty sure both of those do nothing.

if your goal in the latter is to get (256 - Var $0E), you'll want an "INC" after the "EOR #$FF".  and what's at 94/E1D9?

justin3009

Removed the uselessness.  At 94:E1D9 it reloads 7E:000E (Temp X. coordinate).  But that's only if the PC direction is different
'We have to find some way to incorporate the general civilians in the plot.'

'We'll kill off children in the Juuban district with an infection where they cough up blood and are found hanging themselves from cherry blossom trees.'