Mirroring sprites

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
Dimeback
Posts: 10
Joined: Sat Nov 23, 2013 4:23 pm
Location: Papillion, Nebraska

Mirroring sprites

Post by Dimeback » Sat Nov 23, 2013 5:43 pm

Hello. As you can see I am new here. I have a little experience with programming on NES. I have been able to get an animated sprite on the screen that can move and jump using controller input; the basic stuff you all understand. One thing I was wondering how todo is flip the sprite when I press left (the sprites I created are oriented to the right) without having to make a completely new sprite and - as a result - waste graphic space.

lidnariq
Posts: 8704
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Mirroring sprites

Post by lidnariq » Sat Nov 23, 2013 5:50 pm

When you upload your sprites to the NES's sprite control memory, one of the bits in the same byte that controls which set of colors are used will flip each 8x8 or 8x16 sprite.

See http://wiki.nesdev.com/w/index.php/OAM

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Mirroring sprites

Post by tokumaru » Sat Nov 23, 2013 6:05 pm

If your character is wider than 8 pixels, you'll have to worry about more than just the flip bits in the attribute byte though. Typically games make use of meta-sprites (group of hardware sprites that form a larger object), and the meta-sprite system is responsible for reading the sprite definitions and rendering them to OAM taking into consideration the object's position and direction.

Some people would rather avoid the complexity (and slowness) of a routine that automatically flips sprites and define redundant meta-sprites for all directions a character/object can face.

Dimeback
Posts: 10
Joined: Sat Nov 23, 2013 4:23 pm
Location: Papillion, Nebraska

Re: Mirroring sprites

Post by Dimeback » Sat Nov 23, 2013 6:56 pm

My sprite takes up 16x16 pixels. After messing around a bit with the code, I successfully flipped the sprites, but they appear fragmented. How would I get the vertical 8x16 sprites to swap places so it looks normal?

tepples
Posts: 21720
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Mirroring sprites

Post by tepples » Sat Nov 23, 2013 7:13 pm

In your sprite drawing routine, set a variable to 8 if the sprite is not flipped and -8 if the sprite is flipped. Add that value in that variable to the left sprite's X coordinate to get the right sprite's X coordinate.

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Mirroring sprites

Post by tokumaru » Sat Nov 23, 2013 7:28 pm

You have to turn the X coordinate increment into a variable, like tepples said (i.e. to move to the next column of sprites you either add 8 or subtract 8, depending on whether the object is flipped), but you have also to adjust the initial coordinate, so that if the first sprite's X coordinate would be at 231 when not flipped, it would be at 231 + (ObjectWidth - 8) when flipped.

I hope you are not using hardcoded OAM locations for your sprites and updating the coordinates of each individual sprites as your character moves, because that makes things much harder. The correct/versatile way to draw sprites is to start from the object's logical coordinate (the one you use for movement, collisions, etc.) and draw all individual sprites around that, to dynamic OAM positions (which also allows you to do sprite cycling when you need it). As long as you do it the versatile way, it's just a matter of calculating the first X coordinate and the step value based on the direction the object is facing, and use those in the loop that renders sprites.

Dimeback
Posts: 10
Joined: Sat Nov 23, 2013 4:23 pm
Location: Papillion, Nebraska

Re: Mirroring sprites

Post by Dimeback » Wed Nov 27, 2013 9:31 am

tokumaru wrote:I hope you are not using hardcoded OAM locations for your sprites and updating the coordinates of each individual sprites as your character moves, because that makes things much harder. The correct/versatile way to draw sprites is to start from the object's logical coordinate (the one you use for movement, collisions, etc.) and draw all individual sprites around that, to dynamic OAM positions (which also allows you to do sprite cycling when you need it). As long as you do it the versatile way, it's just a matter of calculating the first X coordinate and the step value based on the direction the object is facing, and use those in the loop that renders sprites.
I am not sure what "hardcoded" OAM is. This is what my code for the sprite drawing routine looks like:

Code: Select all

PlayingSP:                 ; This is the code for where the sprites first appear on the screen
     ;vert tile attr horiz
  .db $B0, $00, $00, $20
  .db $B0, $01, $00, $28
  .db $B8, $02, $00, $20
  .db $B8, $03, $00, $28
Should I change it to something like this?

Code: Select all

PlayingSP:                 ; This is the code for where the sprites first appear on the screen
     ;vert tile attr horiz
  .db $B0, $00, $00, $20
  JSR draw_PlayingSP       ; Code will exist soon
Or does it have todo with something else?

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Mirroring sprites

Post by tokumaru » Wed Nov 27, 2013 11:12 am

Dimeback wrote:I am not sure what "hardcoded" OAM is.
Hardcoding an object to OAM locations would be to always have the same object use the same OAM slots. The OAM can hold 64 sprites, if your character is 16x32 pixels large (meaning it needs 8 8x8 sprites) and you always use $0200-$021F (assuming your OAM buffer is at $0200, like in most programs), that would be hardcoding sprites. This is bad because the same characters will always be displayed with the same priority, so if you line up a number of characters that adds up to more than 8 sprites, the ones with lower priority will disappear. This problem is solved by drawing the characters to different OAM slots every frame (meaning you can't hardcode them), so that their priorities cycle and you end up with flicker instead of invisible sprites.

samwise970
Posts: 20
Joined: Tue Oct 17, 2017 12:13 am

Re: Mirroring sprites

Post by samwise970 » Fri Feb 08, 2019 10:36 am

Sorry to bring up such an old thread.. but I figured this is better than starting a completely new one.

How can I set a single bit? This is a lame question. I want to set bit 6 to horizontally mirror a sprite.. and there has to be a better way to do this than:

Code: Select all

  LDX #$40
  CPX $2002 (or non hardcoded address)
  BNE Flip
  JMP DontFlip
Flip:
  LDA $2002
  CLC
  ADC #$40
  STA $2002
DontFlip:
(I realize this wouldn't work on vertically flipped sprites since bit 7 would be set)

I haven't tested but maybe I could do this:

Code: Select all

  LDA $0202
  AND #%01000000
  BEQ DontFlip
Flip:
  CLC
  ADC #$40
  STA $2002
DontFlip:
Is there a better way than this? A way I can change the switch in bit 6 without even checking if it's already set or not? In this case, I just want mirroring turned on, and it seems faster to just change that bit than to check first.

######################
EDIT: Solved, sorry to bother. The answer is to use ORA when trying to set a bit to 1, and AND when setting a bit to 0.
set bit 6 to 1:

Code: Select all

LDA $0202
ORA #%01000000
STA $0202
set bit 6 to 0:

Code: Select all

LDA $0202
AND #%10111111
STA $0202
######################




I hope it's okay cause I'm gonna be asking a lot of dumb questions for a while till I've got the hang.

User avatar
tokumaru
Posts: 11443
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Mirroring sprites

Post by tokumaru » Fri Feb 08, 2019 11:30 am

OR (6502 ORA) is the operation used for setting bits: anything OR 1 equals 1, anything OR 0 remains unchanged.

AND is the operation used for clearing bits: anything AND 0 equals 0, anything AND 1 remains unchanged.

XOR (6502 EOR) is the operation used for inverting bits: anything XOR 1 gets inverted, anything XOR 0 remains unchanged.

Post Reply