Alternative sprite buttons:
a possible alternative to sprite collisions is the use of a spriteIdBitmap.
components.
-
a spritebuttonClass
--> a virtual base class for buttons
-
a spriteVector
--> a vector containing all sprite buttons created. ( vector<spriteButton*> buttonlist; ) .
-
a spriteMap
--> a memoryblock the same size as the screen. ( int size, int height, int data). (links a screen coordinate to a index in the vector<> )
-
a mouse function or class called inside the game loop.
As soon as a button sprite is placed on the screen the spriteMap is altered. The region filled on the screen by the button sprite is 'coloured in' on the sprite map with an integer equal value to the spritebuttons index in the spritelist vector;
the major pro to this system is that you can use the alpha values of the pixels. This enables a form of masking.
I've been trying to work it out and it's going fine, only thing. My sprites starts to flicker when I go over it with the mouse. I guess I'll have to review my sprite knowledege. For now Here is the code so far.
preproccesor.h
/// preprocesor_def.h
/// part of: SPRITEBUTTON & CURSOR toolkit.
/// created: 15 jan 2009
/// version 0.0 :< no warrenties , no support , no guaranties >:
/// reserve a bitmap for working operations. It's best to leave this bitmap
// unused. You could use this bitmap but it will resolve int slower prefromancs
// due to copieing.
#define BITMAPNUMBER_RESERVED_FOR_SYSTEM 32
/// defining start int for sprite and image id'
// you can alter these if nessecary to avoid overlapping sprite or image id.
#define SPRITEBUTTON_SPRITE_ID_START 2
#define SPRITEBUTTON_IMAGE_ID_START 2
spritebutton.h
#define SPB_USE_ALPHA 0x01
#define SPB_DRAG_ENABLED 0x02
#define SPB_HAS_OVER_STATE 0x04
#define SPB_HAS_HIT_STATE 0x08
#define SPB_MOUSE_OVER 0x10
#define SPB_MOUSE_OUT 0x20
#define SPB_MOUSE_DRAGGING 0x40
#define SPB_MOVED 0x80
class spriteButton
{
// declaring friend
friend class cursor;
protected:
unsigned int registerToButtonList(); // registers the button on creation
// returned ID is stored in button_id
void doMouseCode(bool mouseInside, int clickCode);
// dispatcher to mousebuttoncodes
void drawToMap(); // draw to cursor::buttonMap
private:
// standard properties of the button
unsigned char flags;
/// static counter that keeps track of the last created sprite and image id.
static int sprite_id_counter;
static int image_id_counter;
/// the button's Index in the cursor::buttonList;
unsigned int button_id;
/// the image and sprite ID of the up_image
// +1 for over_image
// +2 for down_image
// +3 for mask_image
int local_image_id_base;
int local_sprite_id_base;
// imageID's to use;
int imgNormalState;
int imgOverState;
int imgDownState;
int imgMask;
// spriteID's to use
int sprNormalState;
int sprOverState;
int sprDownState;
/// the position of the button
int xpos;
int ypos;
int width;
int height;
/// mouseInteractionButtons
void onClickLeft(){}; // left mouse button click
void onClickRight(){}; // right mouse button click
void onClickMiddle(){}; // middle mouse button click
void onClickAux(){}; // center mouse button click
void onDoubleClick(){}; // only for left button
void onMouseOver(){};
void onMouseOut(){};
public:
unsigned int get_button_id(){return button_id;};
/// draw functions
void draw(); // draw to screen
bool isDraggable();
bool useAlpha();
spriteButton(int x, int y, char* up_image, char* over_image, char* down_image , char* mask_image, char flags);
spriteButton(int x, int y, char* up_image, char* over_image, char* down_image , char flags);
// spriteButton(int x, int y, int up_image_id, int over_image_id, int hit_image_id /*, char* shapeImageID*/);
};
#ifndef COMPILING_LIBRARY
int spriteButton::sprite_id_counter = SPRITEBUTTON_SPRITE_ID_START;
int spriteButton::image_id_counter = SPRITEBUTTON_IMAGE_ID_START;
#endif
spritebutton.cpp
#include "preprocessor_def.h"
#include "DarkGDK.h"
#include <cassert>
#define COMPILING_LIBRARY
#include "cursor.h"
#include "spriteButton.h"
#undef COMPILING_LIBRARY
//extern unsigned int cursor::add(spriteButton*);
unsigned int spriteButton::registerToButtonList()
{
cursor* c = cursor::instance();
return c->add(this);
}
spriteButton::spriteButton(int x, int y, char* up_image, char* over_image, char* hit_image /*, char* shapeImage*/, char my_flags)
{
button_id = registerToButtonList();
flags = my_flags | SPB_MOVED | SPB_MOUSE_OUT; // use flags and set the mouse outside button
/// storing the position
xpos = x;
ypos = y;
/// setting local base id's
local_image_id_base = image_id_counter;
local_sprite_id_base = sprite_id_counter;
sprite_id_counter+=3;
// loading the images
dbLoadImage(up_image ,image_id_counter++);
dbLoadImage(over_image,image_id_counter++);
dbLoadImage(hit_image ,image_id_counter++);
width = 110;
height= 100;
}
void spriteButton::draw()
{
if (flags & SPB_MOUSE_OVER)
{
// dbText(0,0,"mouseOver");
dbSprite(1 ,xpos ,ypos ,local_image_id_base+1);
// dbSetSpriteAlpha(local_sprite_id_base+1 ,0);
}
if (flags & SPB_MOUSE_OUT)
{
// dbText(0,0,"mouseOut");
dbDeleteSprite(1);
dbSprite(2 , xpos ,ypos ,local_image_id_base);
// dbSetSpriteAlpha(local_sprite_id_base+1 ,255);
}
if (flags & SPB_MOVED)
{
flags = flags^SPB_MOVED;
drawToMap();
}
}
void spriteButton::drawToMap()
{
dbText(20,20,"drawToMap()");
cursor* c = cursor::instance();
if(useAlpha())
{
assert(0);
}
else
{
c->buttonMap->setArea(xpos,ypos,width,height,button_id);
}
}
void spriteButton::doMouseCode(bool mouseInside, int code)
{ // protected
if (mouseInside)
{
flags = (flags | (unsigned char)SPB_MOUSE_OVER) ^ SPB_MOUSE_OUT;
}
else
{
flags = (flags | (unsigned char)SPB_MOUSE_OUT) ^ SPB_MOUSE_OVER;
}
dbText(160,0,"doMouseCode");
if (code | 0x01) {onClickRight();}
if (code | 0x02 ) {onClickLeft();}
if (code | 0x04 ) {onClickMiddle();}
if (code | 0x08 ) {onClickAux();}
}
bool spriteButton::isDraggable(){ return (flags&SPB_DRAG_ENABLED);}
bool spriteButton::useAlpha() { return (flags&SPB_USE_ALPHA);}
cursor.h
#include <vector>
class spriteButton;
class cursor
{
friend class spriteButton;
protected:
cursor();
private:
std::vector<spriteButton*> buttonList;
static cursor* pInstance ;
unsigned int lastButton_id;
class map
{
unsigned int xSize; // width of the map
unsigned int ySize; // height of the map
unsigned int byteSize; // size in bytes of the mapstructure
char* data; // pointer to the data stored in the map
public:
unsigned int getPixel (unsigned int x, unsigned int y);
void setArea (unsigned int x, unsigned int y,unsigned int w,unsigned int h,unsigned int index);
void resize (unsigned int x, unsigned int y);
map(unsigned int width,unsigned int height); // consructor
~map(); // desturctor
}* buttonMap;
public:
static cursor* instance();
void check();
unsigned int add (spriteButton*);
};
#ifdef COMPILE_LIB
cursor.pInstance = NULL;
unsigned int cursor::lastButton_id=0
#endif
cursor.cpp
#include "preprocessor_def.h"
#include "DarkGDK.h"
#define COMPILING_LIBRARY
#include <vector>
#include "spritebutton.h"
#include "cursor.h"
#undef COMPILING_LIBRARY
cursor* cursor::pInstance=NULL;
cursor::cursor() : lastButton_id(0)
{
// create a unique buttonMap
buttonMap = new cursor::map(dbScreenWidth (), dbScreenHeight ());
// insert a null address at vector 0;
buttonList.push_back( NULL );
}
unsigned int cursor::add(spriteButton* btn)
{
buttonList.push_back(btn);
return buttonList.size()-1;
}
cursor* cursor::instance(void)
{ if (cursor::pInstance == NULL)
pInstance = new cursor();
return pInstance;
}
void cursor::check()
{
dbText(20,100,"oldSpriteID");
dbText(120,100,dbStr((int)lastButton_id));
// retreaving currens sprite under the mouse
int spriteID = buttonMap->getPixel(dbMouseX(),dbMouseY());
// reseting the old button
if( lastButton_id != spriteID )
{
if (lastButton_id)
buttonList[lastButton_id]->doMouseCode(false,0); // tell the last button it's no longer
lastButton_id =spriteID;
}
int MouseClickCode = dbMouseClick();
// sending info to the new button
if (spriteID)
{
buttonList[spriteID]->doMouseCode(true,MouseClickCode);
}
dbText(20,80,"spriteID");
dbText(120,80,dbStr(spriteID));
}
///////////////////////////////////////////////////////
/// cursor::map
// constructor
cursor::map::map(unsigned int x,unsigned int y)
{
resize(x,y);
return;
}
// destructor
cursor::map::~map()
{
delete []data;
return;
}
// resize -> resizes the map
void cursor::map::resize(unsigned int x,unsigned int y)
{
xSize = x;
ySize = y;
byteSize = (x * y + 3)*sizeof(int);
// removing the old date
delete []data;
// creating new data
data = new char [x*y*sizeof(int)];
// filling the map with 0 values
setArea(0,0,x,y,0);
return;
}
// getPixel()
unsigned int cursor::map::getPixel(unsigned int x,unsigned int y)
{
unsigned int* reader = (unsigned int*)data;
unsigned int offset = xSize*y+x+3;
reader += offset;
return *reader;
}
// setArea()
void cursor::map::setArea(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int index)
{
unsigned int* writer = ((unsigned int*)data) + 3; // top left corner of datamap
unsigned int* head; // start of a datarow
for (unsigned int h_i = 0; h_i < h; h_i++)
{
if( h_i+y < ySize)
{
head = writer + (y + h_i ) * xSize + x;
for (unsigned int w_i = 0; w_i < w; w_i++)
{
if( w_i+x < xSize)
{
*head = index;
head++;
}
}
}
}
return ;
}
main.cpp
#include "DarkGDK.h"
#include "preprocessor_def.h"
#include "spriteButton.h"
#include "cursor.h"
// the main entry point for the application is this function
void DarkGDK ( void )
{
dbSyncOn ( );
dbSyncRate ( 60 );
cursor* mouseObj = cursor::instance();
spriteButton* test = new spriteButton(100,100,"start1.png", "start2.png","start3.png",0);
while ( LoopGDK ( ) )
{
mouseObj->check();
test->draw();
dbSync ( );
}
return;
}