Here's an example of chain flipping:
This goes in library.c:
Code:
//////////////////////////////////////////////////////////////////////////////
// SetSpriteFlipChain
// Flips a sprite chain
// Inputs:
// SpriteNo - 0-63 the sprite to flip
// XWidth - how many tiles wide the sprite chain is (8 pixels per tile width, so if the sprite is 16 pixels wide, the number of tile width to enter is 2)
// YHeight - how many tiles high the sprite chain is (8 pixels per tile height, so if the sprite is 16 pixels tall, the number of tile height to enter is 2)
// tileCount - number of tiles in chain (if a full rectangle, then XWidth*YHeight, but other orientations with fewer tiles are supported
// HFlip - 1 to flip horizontally
// VFlip - 1 to flip vertically
//////////////////////////////////////////////////////////////////////////////
void SetSpriteFlipChain(u8 SpriteNo, u8 XWidth, u8 YHeight, u8 tileCount, bool HFlip, bool VFlip)
{
u8 i, HFlipped, VFlipped, XMod, YMod, SpriteMods;
u8 * theSprite = SPRITE_RAM;
theSprite += (SpriteNo * 4); //Set up pointer to tile in VRAM
SpriteMods = *(theSprite+1);
HFlipped = SpriteMods>>7; //get the tile's stored value for Horizontal Flip from VRAM(0=normal,1=flipped)
VFlipped = SpriteMods<<1;
VFlipped = VFlipped>>7; //get the tile's stored value for Vertical Flip from VRAM(0=normal,1=flipped)
XMod=1;
YMod=1;
if(HFlip){
XMod=-1; //if HFlip, then set the X Modifier to -1 to invert the X offset for dependent tiles in the chain
if(XWidth){
if(HFlipped){ //Check if main tile is already Horizontally flipped and manage X position when flipping, so that the chain occupies the same space when flipped or flipped back
*(theSprite+2)-=(XWidth*8-8);
}else{
*(theSprite+2)+=(XWidth*8-8);
}
}
}
if(VFlip){
YMod=-1; //if VFlip, then set the Y Modifier to -1 to invert the Y offset for dependent tiles in the chain
if(YHeight){
if(VFlipped>0){//Check if main tile is already Verically flipped and manage Y position when flipping, so that the chain occupies the same space when flipped or flipped back
*(theSprite+3)-=(YHeight*8-8);
}else{
*(theSprite+3)+=(YHeight*8-8);
}
}
}
for (i = 0; i < tileCount; i ++) //Loop through all tiles in the chain
{
SetSpriteFlip(SpriteNo + i, HFlip, VFlip); //Flip the tile
if(i>0){//Manage offset modifiers for all dependent tiles
theSprite += (4);
*(theSprite+2) *= XMod; //if XMod is -1, then offset gets inverted
*(theSprite+3) *= YMod; //if YMod is -1, then offset gets inverted
}
}
}
This goes in library.h:
Code:
void SetSpriteFlip(u8 SpriteNo, bool HFlip, bool VFlip);
void SetSpriteFlipChain(u8 SpriteNo, u8 XWidth, u8 YHeight, u8 tileCount, bool HFlip, bool VFlip);
Note 1: The chain flipping formula edits the X and/or Y position of the main tile to make it so that, when flipped, the chain remains in the same space on the screen. If something else is directly modifying/setting sprite position outside of this formula, then the effect of this corrective measure is override and will appear not to have worked. In that case, the tile chain will pivot on the coordinates of the main tile, and the flipped chain will occupy space outside of the chain in its un-flipped state.
Note 2: The reason tileCount is required is to allow support for sprite chains that do not fill a full rectangle, otherwise tileCount would equal XWidth*YHeight.
Note 3: XWidth and XHeight are used to determine how far the main tile should be moved when flipped. Assuming that the main tile is the uppermost and leftmost tile in the chain, then the XWidth and XHeight would be the full number of tiles horizontally and vertically, respectivly. For example, if a chain is flipped vertically, the uppermost leftmost tile becomes the lowermost leftmost tile, and will be moved down into that position. If the main sprite is offset from the leftmost uppermost tile, then XWidth and XHieght need to be figured out based on that offset to determine the pivot point.
Say you have a tile chain like this where the main tile is at the top and in the middle, and you've got 4 total tiles.
X
XXX
You would want horizontal flipping to pivot directly on the coordinates of the main tile and the main tile would not need to change position in that case. Therefore XWidth could be set to 0, and Y Height would be set to 2, while tileCount is set to 4.
Examples of 2 sprite groups at the bottom that are not full rectangles. The lower left is an example of a main tile being offset from the left by 1 tile, and the lower right is a chain were there is a gap between the main tile and the first dependent. In both cases, the entire chain stays within the same space when flipped.