Sprite Engine Help

SGDK only sub forum

Moderator: Stef

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Sprite Engine Help

Post by MrTamk1s » Sat May 16, 2015 2:30 am

So I am trying to get an Eagle sprite to appear and fly across the screen for the "FMV" intro on my Ultra Air Hockey homebrew game, but, despite analyzing the Sonic SGDK sprite sample and the SGDK doxygen documentation to death, can't seem to get the Eagle to appear, despite following (what I think is) the basic principle. By "Sprite Engine", I am referring to the newly introduced methods in "sprite_Eng.h", not the "vdp_spr.h" methods. I am currently refactoring the project from a failed BEX attempt to an improved SGDK attempt, since it has more features I need built-in (sprite collision, trigonmetry, fixed-point, etc).

Anyways, the main problem is that the sprite's tiles do not upload to the VDP VRAM and the 1st VDP sprite list entry does not update for the sprite, according to Gen's VDP debug screen. The eagle does not appear at all. My sprite is supposed to have only 1 animation with 1 frame; however, I added a dummy frame to the spritesheet just in case an actual array of frames is needed for the SpriteDefinition struct. I noticed in the Sonic example, no VDP_ methods are used to upload the sprite's tiles, so I am assuming that the SPR_initSprite() method actually uploads the tiles to the VDP VRAM's offset for the sprite engine tile cache.

I start my FMV code by loading a background image, initializing the sprite engine to 15 tiles for the eagle, and verifying that the Sprite Engine does indeed init (it does, because "PASS!" is displayed on the screen). I then initialize the sprite's properties using PAL2 as the palette, set PAL2's contents to its palette, and then set the sprite's animation and frame to 0,0. Lastly, I move the Eagle across the screen, and display the foreground text image afterwards.

To show what the FMV is supposed to do but doesn't:
Old BEX FMV
New SGDK FMV (bugged)

Relevant and abridged code:

FMV.c:

Code: Select all

//Holds EagleSoft Ltd and Title FMV sequences
#include "../inc/fmv.h"

//EagleSoft Ltd FMV Sequence
void FMV()
{
    //Variables
    u16 x=0x80;         //x value of Eagle Sprite
    const u16 y=0xF0;   //y value of Eagle Sprite
    u16 offset;         //Tile offset for Eagle tiles
    Sprite sprites[1];  //Sprite struct

    VDP_clearPlan(APLAN,0);     //Clear VDP Plans A & B
    VDP_clearPlan(BPLAN,0);

    SYS_disableInts();                          //Disable interrupts
    VDP_setScreenWidth320();                    //320x224 VDP mode
    echo_play_sfx(SFX_33);                      //Play EagleSoft Ltd sfx song
    VDP_setPaletteColors(0, palette_black, 64); //reset all palette to black
    DrawBG(18);                                 //Draw EagleSoft Ltd BG (Plane A)
    SYS_enableInts();                                                                   //Enable interrupts

    SPR_init(15);

    if (SPR_isInitialized()==_FALSE)
    {
        VDP_setTextPalette(PAL0);
        VDP_drawText("FAIL!",1,1);
    }
    else
    {
        VDP_setTextPalette(PAL0);
        VDP_drawText("PASS!",1,1);
    }
                                                                         //Allocate 15 tiles for Eagle Sprite
    offset=TILE_USERINDEX+(FMV_BG.tileset->numTile)+(FMV_Text.tileset->numTile);        //Get tile offset for Eagle
    SPR_initSprite(&sprites[0], &SPR_Eagle, x, y, TILE_ATTR(PAL2,TRUE,FALSE,FALSE));    //Init the Eagle Sprite
    SPR_update(sprites, 1);             //Update it
    //VDP_setSprite(0, x, y, SPRITE_SIZE(4,3), TILE_ATTR_FULL(PAL1,1,0,0,offset), 0);   //Setup the sprite
    VDP_setPalette(PAL2, SPR_Eagle.palette);                                          //Init palette PAL2 to Eagle palette
    SPR_setAnimAndFrame(&sprites[0], 0,0);                                              //Set to 0th animation
    //VDP_loadTileData(SPR_Eagle, Eagle_voff, 12, 0); //Get Sprite Tile Data

    //Move the Eagle from left to right on screen
    for (x=0x80;x<=0x1C0;x+=1)
    {
            SPR_setPosition(&sprites[0],x,y);   //Set new position
            SPR_update(sprites, 1);             //Update it
            VDP_waitVSync();                    //Sync
    }

    DrawBG(19);                 //Draw plane B of EagleSoft Ltd (text/logo)
    waitMs(1000);               //Wait 1s
    VDP_fadeOutAll(1000,0);     //Fade in 1s
    SPR_end;                    //Kill sprite engine
}
fmv.h:

Code: Select all

#include <Genesis.h>
#include <timer.h>
#include "../res/Gfx/Planes.h"
#include "../res/Gfx/Sprites.h"
#include <sprite_eng.h>
#include "../inc/main.h"
#include <vdp_pal.h>

void FMV();
void Title();
Sprites.res:

Code: Select all

//Gets 4x3 tile-sized sprites from a 8x3 tile-sized spritesheet (therefore, 2 sprites)
SPRITE SPR_Eagle "FMV\Eagle.png" 4 3 0 5
Sprites.h:

Code: Select all

#ifndef _SPRITES_H_
#define _SPRITES_H_

extern const SpriteDefinition SPR_Eagle;

#endif // _SPRITES_H_
Also, some images showing the active screen and VDP VRAM/Sprite Debug data:

Image

Image
Image

...and the current ROM source

What am I doing wrong? I really need to learn how to fix this, and deal with the sprite engine in order to fix the FMV, and, more importantly, begin working on puck and paddle movement and collisions.

Thanks in advanced!
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Stef
Very interested
Posts: 3043
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Sat May 16, 2015 9:29 pm

Actually the parameter you pass to SPR_init(..) should not be that low !
It is actually the size of the tile cache and not the number of tiles your sprite(s) is using. Actually i believe even the single eagle sprite is using more than 15 tiles (4x4 ?) so it won't be able to even allocate its tilemap.
The default value for tile cache size is 384 tiles and a good number is at least 256 tiles ;)

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Post by MrTamk1s » Sat May 16, 2015 10:31 pm

Stef wrote:Actually the parameter you pass to SPR_init(..) should not be that low !
It is actually the size of the tile cache and not the number of tiles your sprite(s) is using. Actually i believe even the single eagle sprite is using more than 15 tiles (4x4 ?) so it won't be able to even allocate its tilemap.
The default value for tile cache size is 384 tiles and a good number is at least 256 tiles ;)
I changed the command to SPR_Init(384);

Looks like I forgot to add a SPR_setVRAMTileIndex command to set the Tile Cache to the VRAM offset

Changed this part of the code to this:

Code: Select all

offset=TILE_USERINDEX+(FMV_BG.tileset->numTile)+(FMV_Text.tileset->numTile);        //Get tile offset for Eagle
    [b]SPR_setVRAMTileIndex(&SPR_Eagle,offset);[b]
    SPR_initSprite(&sprites[0], &SPR_Eagle, x, y, TILE_ATTR(PAL2,TRUE,FALSE,FALSE));    //Init the Eagle Sprite
    SPR_update(sprites, 1);             //Update it
I also tried various combinations for the SPR_setVRAMTileIndex() command to get the sprite to appear, both with auto VRAM allocation and at the VRAM offset, including:

SPR_setVRAMTileIndex(&sprites[0],-1);
SPR_setVRAMTileIndex(&sprites[0],offset);
SPR_setVRAMTileIndex(&sprites,-1);
SPR_setVRAMTileIndex(&sprites,offset);
SPR_setVRAMTileIndex(&SPR_Eagle,-1);
SPR_setVRAMTileIndex(&SPR_Eagle,offset);

Some combination corrupted the entire VRAM, both tiles and the Sprite list, while others kept the VRAM the same, but still did not upload the eagle tiles nor changed the 1st entry in the sprite list.[/list]
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Stef
Very interested
Posts: 3043
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon May 18, 2015 9:31 am

No you don't need to use the SPR_setVRAMTileIndex(..) method except if you want to force a manual allocation of the tiles in VRAM. By default the sprite engine handle the VRAM allocation for you as you can see in the "Sprite" sample.

Actually using:

Code: Select all

// init sprite engine
SPR_Init(256);
...
// init sprite
SPR_initSprite(&sprites[0], &SPR_Eagle, x, 128, TILE_ATTR(PAL2,TRUE,FALSE,FALSE));
// set palette
VDP_setPalette(PAL2, SPR_Eagle.palette);
...
for(x = 0; x <= 320; x++) 
{
    SPR_setPosition(&sprites[0], x, 128);
    SPR_update(sprites, 1);
    VDP_waitVSync();
}
should be enough.

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Post by MrTamk1s » Wed May 27, 2015 1:07 am

What you posted worked, the Eagle tiles are now uploaded and the Eagle sprite now flies across the screen! (Although the sprite tiles overwrite a small section of the Plane A BG; though, I should be able to fix this.)

Thanks!
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Post by MrTamk1s » Wed May 27, 2015 1:59 am

Sorry for the double post, but one last minor issue; the code from above does not properly load the correct colors from the Eagle Sprite image into PAL2.

(Specifically,

Code: Select all

VDP_setPalette(PAL2, SPR_Eagle.palette);
does not seem to be working correctly)

I verified that Rescomp does indeed create the correct palette from the sprite, by copying the palette from the sprites.s file and hardcoding the game to load those colors from a u16 hex array, which causes the correct colors to be allocated. Appears I am accessing and uploading the palette data to CRAM incorrectly; what is the proper way to do this without hardcoding sprite palette data?
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Stef
Very interested
Posts: 3043
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Wed May 27, 2015 10:56 am

MrTamk1s wrote:Sorry for the double post, but one last minor issue; the code from above does not properly load the correct colors from the Eagle Sprite image into PAL2.

Code: Select all

VDP_setPalette(PAL2, SPR_Eagle.palette);
Oh yeah indeed you have to use:

Code: Select all

VDP_setPalette(PAL2, SPR_Eagle.palette->data);
I know, i need to add methods to properly load the Palette structure directly :)

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Post by MrTamk1s » Mon Jun 01, 2015 12:53 pm

That fixed the palette issue :).
==================

Another problem with the Sprite Engine regarding setting collision properties. After using rescomp with "BOX" or "CIRCLE" collision types for my in-game sprites, Code::Blocks threw errors of invalid M68k datatype declaration opcodes in the corresponding .s files during compilation. Upon opening those .s files, saw that Rescomp appeared to have appended internal variable names from somewhere as data types (it created invalid M68k opcodes such as as "dc.x", "dc.y", and "dc.ray" :?). IIRC, these invalid opcodes were created for the last frame declaration of each animation in the spritesheets, and that declaration had 2 entries, one which appeared valid, the other with the invalid opcodes.

Attempting to remove the invalid entry and recompiling still generated errors. Currently, I am omitting the last three params for the rescomp SPRITE definitions until I actually work on collision code. Not sure if this is an issue with my individual project or Rescomp in general for SPRITE, but it could be a boundary condition defect.

I will show the exact problem when I return home from work :wink:
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Stef
Very interested
Posts: 3043
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Post by Stef » Mon Jun 01, 2015 10:16 pm

To be honest i never tested the collision stuff as it is not yet really implemented so there is great chance of meeting bugs on that specific part !
Thanks for reporting, i will have a look in that !

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Post by MrTamk1s » Tue Jul 28, 2015 1:15 am

Another quick question about the Sprite Engine; regarding the Sprite struct, how can I traverse the Sprite struct to retrieve the width and height of a sprite from its SpriteDef (abbreviated, not SpriteDefinition)? I would want to get the tile width and height of the sprite, so I could then calculate the center coordinate and the other four corners' coordinates of the sprite's box (for collision purposes).
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Stef
Very interested
Posts: 3043
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Sprite Engine Help

Post by Stef » Mon Oct 26, 2015 11:22 pm

Sorry i didn't saw your last message ! I'm not sure i really understand it. Do you want to retrieve the sprite bounding box from the "Sprite" structure ? or from the SpriteDefinition structure ? 'SpriteDef' structure is the old structure used by vdp_spr unit but has nothing to do with the new sprite engine.

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Re: Sprite Engine Help

Post by MrTamk1s » Wed Oct 28, 2015 7:16 pm

Stef wrote:Sorry i didn't saw your last message ! I'm not sure i really understand it. Do you want to retrieve the sprite bounding box from the "Sprite" structure ? or from the SpriteDefinition structure ? 'SpriteDef' structure is the old structure used by vdp_spr unit but has nothing to do with the new sprite engine.
Thanks for clarifying the difference between Sprite, SpriteDefinition, and SpriteDef.

IIRC, I would like to find the sprite bounding box (for collision processing) if the corner coordinates are somewhere in the Sprite struct or its children structs, if the BOX/CIRCLE collision types are now fixed. And if that is not possible, then a way to access the sprite's tile width/height, in order to calculate the box's corner offsets from the sprite's x/y position (which is at sprite's top left corner).

Sorry if this is vague, but my laptop has been dead for the past month, and I don't have access to Code::Blocks w/ SGDK at the moment.
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Stef
Very interested
Posts: 3043
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Sprite Engine Help

Post by Stef » Thu Oct 29, 2015 12:12 pm

Ok, so to get the sprite bounding box you can use this (using the Sprite object) :

Code: Select all

// top left corner in pixel
sprite->x;
sprite->y;
// width and height of current sprite frame in pixel
sprite->frame->w;
sprite->frame->h;

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Re: Sprite Engine Help

Post by MrTamk1s » Thu Nov 12, 2015 5:25 pm

That should be what I need to calculated the bounding box; thanks!
Will try it when I next reinstall SGDK/Code::Blocks and resume programming
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

MrTamk1s
Very interested
Posts: 75
Joined: Sun Jan 04, 2015 10:27 pm
Location: Pennsylvania
Contact:

Re: Sprite Engine Help

Post by MrTamk1s » Tue Jan 12, 2016 1:12 am

Got the bounding boxes and collision to work with that code for paddle-puck collisions.

Next important graphics-related issues to fix are some sprites disappearing and issues with the Player select screen. Not sure why, but when I enable the powerups options variables (Opts[2]=PTRUE in main.h) and the game attempts to display the saved and active powerups for each player on the HUD, all of the sprites in game become invisible. In Gen's VDP VRAM debugger, the VRAM still holds the sprites, but they are not appearing. What in my code is causing this (I suspect pointer issues or badly timed interrupts at play)? Relevant code in game.c, functions InitGame() and HUD().

Also, for the Player Select screen, On Real Hardware and Exodus, the game crashes with an address error. Also at that screen, an Arrow sprite (meant to point to the # of players selected) never appears (and is never loaded into VRAM), and the full-screen background is shifted many pixels and miscolored. Relevant code at Menu.c, function ChrselMenu(), and DrawBG.c, function DrawBG() case 8. (Do note that, for now, the code to load arrow sprite into VRAM is commented).

Thanks in advance!
SGDK homebrew dev and Unity3D Indie dev.
Sega does what Nintendont!

Post Reply