Cursor control problems with SDL - Almost done..just one more thing
Hi all.
I'm having problems with my cursor control modules. I've decided that my engine will take over cursor processign when ever it is instansiated. The reasons for this is that SDL (my API of choice at the moment) doesn't automatically provide cursor processing in fullscreen mode.
Anyway. I've got a cursor class that is dervived from my base sprite class. I'm calling the cursor control during each iteration of the game loop, clearing the old position, calling pumpevents and the SDL_GetRelativeMouseState() for the X and Y deltas, adding the new X and Y to the current X and Y values and then redrawing the cursor sprite.
The old position of the cursor isn't being removed, the new cursors Y coordinates doesn't seem to change and the cursor movement isn't smooth at all. I've also noticed that if something is happening on screen, ie. I'm drawing something else, then that stops while the cursor is being moved. I'm assuming that the get mouse state functions wait until there is no mouse movement/action before returning?
Does anyone know of any tutorials regarding SDL and cursor controls. The SDL documentation is pretty scant for this?
[Edited by - garyfletcher on May 23, 2005 5:26:23 PM]
Well, SDL kind of is too low level to support that stuff.
You will have to post some sort of source code for any help...my only idea from what i can see is that the SDL mouse positions are right (the delta's it returns with SDL_GetRelative...() ), but since it has to wait to draw it, the delta's just keep adding up...like the mouse is moving, it just doesnt draw until everything else is done.
But then again, some code would help...
You will have to post some sort of source code for any help...my only idea from what i can see is that the SDL mouse positions are right (the delta's it returns with SDL_GetRelative...() ), but since it has to wait to draw it, the delta's just keep adding up...like the mouse is moving, it just doesnt draw until everything else is done.
But then again, some code would help...
Okay. I'll post code. I was trying to avoid this coz it's pretty long.
I'll Add an explination of how the sprites are used as well. Code 1st though..:)
Cursor class:
Base sprite class:
animation class:
game loop (called from stack):
In order to load multiple animations for a sprite I use a map of animations using a key to indicate which animations we are currently working on. So to inistansiate a sprite an key is set and a set of animations or a single frame loaded into the sprite:
/* Cursor */
baseCursor = new SiSEAnimation("cursor/CursInfo");
clearCursor = new SiSEAnimation("cursor/ClearCursInfo");
cursor = new SiSECursor(m_Window,250.0f,250.0f);
cursor->setAnimKey(CLEARKEY);
cursor->m_addAnimation(clearCursor);
cursor->setAnimKey(CURSKEY);
cursor->m_addAnimation(baseCursor);
Hope someone can help..:)
For anyone interested the Vector2D class is shown below:
[Edited by - garyfletcher on May 23, 2005 1:45:49 AM]
I'll Add an explination of how the sprites are used as well. Code 1st though..:)
Cursor class:
#ifndef INCLUDE_CURSOR_H#define INCLUDE_CURSOR_H#include "SiSEBaseSprite.h"#include "SiSEVector2D.h"const std::string CURSKEY = "CURSKEY";const std::string CLEARKEY = "CURSCLEARKEY";class SiSECursor : public SiSEBaseSprite{ public: SiSECursor(SDL_Surface *screen, float x = 0.0f, float y = 0.0f, float speed = 0.0f); ~SiSECursor(); void mProcessCursor(void); inline void mEnableCurs(void){mEnabled = true;} inline void mDisableCurs(void){mEnabled = false;} inline void mToggleCurs(void){mEnabled = !mEnabled;} inline bool mIsEnabled(void){return mEnabled;} inline void mSetClearKey(std::string& clrKey){mClearKey = clrKey;} inline void mSetCursKey(std::string& cursKey){mCursAnimKey = cursKey;} inline void mSetDefaults(void){mClearKey = CLEARKEY; mCursAnimKey = CLEARKEY;} private: void mSetCursPos(void); void mAddRelCursPos(void); void mGetCursPos(void); bool mEnabled; int mouseAX; int mouseAY; int mouseRX; int mouseRY; int button; std::string mClearKey; std::string mCursAnimKey; };#endif#include "SiSECursor.h"#include "SDL/SDL.h" enum MBUTTONS{NONPRESSED,LPRESSED,RPRESSED}; SiSECursor::SiSECursor(SDL_Surface *screen, float x, float y, float speed) : SiSEBaseSprite(screen,x,y,speed){ SDL_ShowCursor(SDL_DISABLE); mEnabled = true; mouseAX=0; mouseAY=0; mouseRX=0; mouseRY=0; button=NONPRESSED; mCursAnimKey = CURSKEY; mClearKey = CLEARKEY;}SiSECursor::~SiSECursor(){ mEnabled = false; SDL_ShowCursor(SDL_ENABLE);}void SiSECursor::mProcessCursor(){ if (mEnabled) { mGetCursPos(); mAddRelCursPos(); mAnimKey = mClearKey; clearBG(); mAnimKey = mCursAnimKey; draw(); } return;}void SiSECursor::mAddRelCursPos(){ std::cerr << "mAddRelCursPos() - mouseRX: " << mouseRX << std::endl; std::cerr << "mAddRelCursPos() - mouseRY: " << mouseRY << std::endl; xyAdd(mouseRX,mouseRY);}void SiSECursor::mSetCursPos(){ xySet(mouseAX,mouseAY); } void SiSECursor::mGetCursPos(){ mouseAX=0; mouseAY=0; mouseRX=0; mouseRY=0; button=NONPRESSED; int height = GetHeight(); int width = GetWidth(); SDL_PumpEvents(); SDL_GetMouseState(&mouseAX,&mouseAY); if (mouseAX < 0) { mouseAX = 0; } else if (mouseAX > height) { mouseAX = height; } if (mouseAY < 0) { mouseAY = 0; } else if (mouseAY > width) { mouseAY = width; } SDL_PumpEvents(); SDL_GetRelativeMouseState(&mouseRX,&mouseRY); if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT)) { button = LPRESSED; } else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT)) { button = RPRESSED; }}
Base sprite class:
#ifndef INCLUDE_BSPRITE_H#define INCLUDE_BSPRITE_H#include <map>#include <string>#include "SiSEAnimation.h"#include "SiSEVector2D.h"enum SpriteState{NORMAL,HIT,COLLISION,CRITICAL,FIRE,JUMP,LEFT,RIGHT,UP,DOWN,STRAFFE,SPIN,SPINRIGHT,SPINLEFT};class SiSEBaseSprite{ public: SiSEBaseSprite(SDL_Surface *screen, float x = 0.0f, float y = 0.0f, float speed = 0.0f); // Constructor ~SiSEBaseSprite(); // Destructor void m_addAnimation(SiSEAnimation* SAnim); // Drawing functions void draw(); void clearBG(); void updateBG(); void DrawSpriteIMG(SDL_Surface *img, float x, float y); void mDrawSprite(void); // Accessor functions Vector2D* Pos(void){return pos;} Vector2D* OldPos(void){return oldPos;} int GetHeight(void){return m_getAnimation()->mGetHeight();} int GetWidth(void){return m_getAnimation()->mGetWidth();} void SetFrame(int nr){mFrame = nr;} int GetFrame(void){return mFrame;} void SetSpeed(float nr){mSpeed = nr;} float GetSpeed(void){return mSpeed;} void SetScreen(SDL_Surface *aScreen){mScreen = aScreen;} SDL_Surface* GetScreen(void){return mScreen;} SpriteState GetState(void){return mState;} // Animations control functions void ToggleAnim(void){mAnimating = !mAnimating;} void StartAnim(void){mAnimating = true;} void StopAnim(void){mAnimating = false;} void Rewind(void){mFrame = 0;} bool isAnimating(); void setAnimKey(const std::string& animKey){mAnimKey = animKey;} // COORD control functions void xAdd(float nr); void yAdd(float nr); void xyAdd(float x, float y); void xSet(float nr); void ySet(float nr); void xySet(float x, float y); protected: int mFrame; // Animation frame tracker // Coordinate vectors Vector2D* pos; Vector2D* oldPos; std::string mAnimKey; // Animation key bool mDrawn; // Drawn flag bool mAnimating; float mSpeed; // Speed indicator (pause multiplier) long mLastUpdate; // Time sprite was last animated SiSEAnimation* mSpriteAnim; // Pointer to animations (sprite frames) typedef std::map<std::string, SiSEAnimation*> mAnimMap; typedef std::pair<std::string, SiSEAnimation*> mAnimPair; mAnimMap mAnimations; SDL_Surface* mScreen; // Pointer to the surface to animate on SiSEAnimation* m_getAnimation(); SpriteState mState; };#endif#include <cmath>#include "SiSEBaseSprite.h"#include "SiSEException.h"SiSEBaseSprite::SiSEBaseSprite(SDL_Surface *screen, float x, float y, float speed){ mFrame = 0; // Animation frame tracker mDrawn = false; // Drawn flag mSpeed = speed; // Speed indicator (pause multiplier) mLastUpdate = 0L; // Time sprite was last animated mSpriteAnim = 0; // Pointer to animations (sprite frames) mState = NORMAL; // Set Sprite state mScreen = screen; // Set screen for output mAnimating = false; // Coordinaye vectors pos = new Vector2D(x,y); oldPos = new Vector2D();} SiSEBaseSprite::~SiSEBaseSprite(){ mSpriteAnim = 0; delete pos; pos = 0; delete oldPos; oldPos = 0; mAnimMap::iterator animIter = mAnimations.begin(); mAnimMap::const_iterator animEnd = mAnimations.end(); while(animIter != animEnd) { delete animIter->second; animIter->second = 0; ++animIter; }}void SiSEBaseSprite::m_addAnimation(SiSEAnimation* SAnim){ mAnimMap::iterator animIter = mAnimations.find(mAnimKey); if (animIter == mAnimations.end()) { mAnimations.insert(mAnimPair(mAnimKey,SAnim)); if (SAnim->mGetFramesNum() > 1) mAnimating = true; } else { throw SiSEException("SiSEBaseSprite() ERROR: Duplicate Animation key."); } return; }bool SiSEBaseSprite::isAnimating(){ mAnimMap::iterator animIter = mAnimations.find(mAnimKey); if (animIter != mAnimations.end()) { return animIter->second->isAnimating(); } else { throw SiSEException("SiSEBaseSprite() isAnimating() ERROR: Cannot find Animation key."); }}void SiSEBaseSprite::xyAdd(float x, float y){ oldPos = pos; pos->SetX(pos->GetX()+x); pos->SetX(pos->GetY()+y);};void SiSEBaseSprite::xAdd(float nr){ oldPos = pos; pos->SetX(pos->GetX()+nr); return;}void SiSEBaseSprite::yAdd(float nr){ oldPos = pos; pos->SetY(pos->GetY()+nr); return; } void SiSEBaseSprite::xSet(float nr){ oldPos = pos; pos->SetX(nr); return; } void SiSEBaseSprite::ySet(float nr){ oldPos = pos; pos->SetY(nr); return; } void SiSEBaseSprite::xySet(float x, float y){ oldPos = pos; pos->SetXY(x,y); return; }SiSEAnimation* SiSEBaseSprite::m_getAnimation(){ mAnimMap::iterator mapIter = mAnimations.find(mAnimKey); if (mapIter != mAnimations.end()) { return mapIter->second; } else { std::string errMsg = "SiSEBaseSprite draw() ERROR: Unable to find animation key " + mAnimKey; throw SiSEException(errMsg); }}// Drawing functionsvoid SiSEBaseSprite::draw(){ mSpriteAnim = m_getAnimation(); int numFrames = mSpriteAnim->mGetFramesNum(); if(numFrames > 1 && mAnimating) { if((mLastUpdate+mSpriteAnim->mAnim[mFrame]->pause*mSpeed) < SDL_GetTicks()) { if (mFrame > (numFrames-1)) { mFrame = 0; } mLastUpdate = SDL_GetTicks(); } } DrawSpriteIMG(mSpriteAnim->mAnim[mFrame]->image, pos->GetX(), pos->GetY()); if(!mDrawn) { mDrawn = true; } return;}void SiSEBaseSprite::DrawSpriteIMG(SDL_Surface *img, float x, float y){ SDL_Rect dest; dest.x = (Sint16)x; dest.y = (Sint16)y; SDL_BlitSurface(img, NULL, mScreen, &dest); return;} void SiSEBaseSprite::clearBG(){ if(mDrawn) { mSpriteAnim = m_getAnimation(); SDL_Rect dest; dest.x = (Sint16)oldPos->GetX(); dest.y = (Sint16)oldPos->GetY(); dest.w = mSpriteAnim->mGetWidth(); dest.h = mSpriteAnim->mGetHeight(); SDL_BlitSurface(mSpriteAnim->mAnim[0]->image, NULL, mScreen, &dest); //DrawSpriteIMG(mSpriteAnim->mAnim[mFrame]->image, pos->GetX(), pos->GetY()); } return; }void SiSEBaseSprite::updateBG(){ SDL_Rect srcRect; mSpriteAnim = m_getAnimation(); srcRect.w = mSpriteAnim->mGetWidth(); srcRect.h = mSpriteAnim->mGetHeight(); srcRect.x = (Sint16)pos->GetX(); srcRect.y = (Sint16)pos->GetY(); oldPos = pos; SDL_BlitSurface(mScreen, &srcRect, mSpriteAnim->mAnim[mFrame]->image, NULL); //DrawSpriteIMG(mSpriteAnim->mAnim[mFrame]->image, pos->GetX(), pos->GetY()); return;}void SiSEBaseSprite::mDrawSprite(){ //clearBG(); //updateBG(); draw(); return; }
animation class:
#ifndef INCLUDE_SISEANIM_H#define INCLUDE_SISEANIM_H#include <string>#include <vector>#include "SDL/SDL.h"class SiSEAnimation{ private: typedef struct { SDL_Surface *image; // Pointer to frame image int pause; // Milliseconds to pause after drawing image } SiSEFrame; bool mBuilt; bool mAnimating; int mNumFrames; int mWidth; int mHeight; public: SiSEAnimation(const std::string& SpriteFile); // Constructor ~SiSEAnimation(); // Destructor // Pointer to animations frames std::vector<SiSEFrame*> mAnim; typedef std::vector<SiSEFrame*>::iterator animIter; typedef std::vector<SiSEFrame*>::const_iterator canimIter; // Accessor functions inline std::vector<SiSEFrame*>& mGetFrames(void){return mAnim;} inline bool mIsBuilt(void){return mBuilt;} inline int mGetFramesNum(void){return mNumFrames;} inline int mGetWidth(void){return mWidth;} inline int mGetHeight(void){return mHeight;} inline animIter mAnimStart(){return mAnim.begin();} inline animIter mAnimEnd(){return mAnim.end();} inline bool isAnimating(void){return mAnimating;} };#endif#include <cstdlib>#include <iostream>#include <fstream>#include "SiSEAnimation.h"#include "SiSEException.h"using std::string;using std::cerr;using std::endl;using std::ifstream;SiSEAnimation::SiSEAnimation(const string& SpriteFile){ mNumFrames = 0; string buffer; string fileName; string name; int pause = 0; int red = 0; int green = 0; int blue = 0; FILE *fp = 0; mWidth = 0; mHeight = 0; mAnimating = false; // Get our information file for this sprite animation fileName = SpriteFile; ifstream inFile(fileName.c_str()); if (!inFile) { std::string ErrMsg = "SiSEAnimation() ERROR: Cannot open " + fileName; throw SiSEException(ErrMsg); } getline(inFile,buffer); sscanf(buffer.c_str(),"FILES: %d",&mNumFrames); //mAnim = new SiSEFrame[mNumFrames]; mAnim.reserve(mNumFrames); mBuilt = true; int frameCount = 0; while(getline(inFile,buffer)) { // check for a valid line if (buffer[0] != '#' && buffer[0] != '\r' && buffer[0] != '\0' && buffer[0] != '\n' && buffer.size() != 0) { char tmpName[50]; memset(tmpName,0,sizeof(tmpName)); // Read our animation data sscanf(buffer.c_str(),"%s %d %d %d %d",tmpName,&pause,&red,&green,&blue); name = tmpName; // set the sprite file for the current animation frame fileName = name; // Read in the current frame SDL_Surface *temp = 0; if ((temp = SDL_LoadBMP(fileName.c_str())) == NULL) { std::string ErrMsg = "SiSEAnimation() ERROR: " + static_cast<string>(SDL_GetError()); throw SiSEException(ErrMsg); } // Check the transprancy colour for the animation if (red >= 0) { SDL_SetColorKey(temp, SDL_SRCCOLORKEY,SDL_MapRGB(temp->format,red,green,blue)); } // Set the current animation frame to the currently read sprite // Just set the formats to help speed things up a little when blitting SiSEFrame* tempFrame = new SiSEFrame; tempFrame->image = SDL_DisplayFormat(temp); // Free the temp memory SDL_FreeSurface(temp); // Set the pause value tempFrame->pause = pause; // Set the width and height if we need to if (!mWidth) { mWidth = tempFrame->image->w; } if (!mHeight) { mHeight = tempFrame->image->h; } mAnim.push_back(tempFrame); // No dangling tempFrame = 0; // Update the count for next one frameCount++; } } if (frameCount > 1) mAnimating = true; inFile.close(); }SiSEAnimation::~SiSEAnimation(){ animIter aIter = mAnim.begin(); canimIter animEnd = mAnim.end(); while (aIter != animEnd) { delete *aIter; *aIter = 0; ++aIter; } }
game loop (called from stack):
void SiSE::m_gameLoop(void){ /* The game loop. Loop until the game stack is empty */ while(!m_StateStack.empty()) { if ((SDL_GetTicks() - m_Timer) >= FRAME_RATE) { /* In order to use the function pointed to on top of the stack */ /* it needs to be called with an object of the appropriate type */ /* In this case a SiSE object. Pass the function pointer */ /* to a member function that will execute it as (this->*funcPtr)() */ ExecuteFunc(m_StateStack.top().funcPtr); // Do cursor processing cerr << "About to process cursor" << endl; cursor->mProcessCursor(); cerr << "Cursor processed" << endl; m_Timer = SDL_GetTicks(); } } return; }
In order to load multiple animations for a sprite I use a map of animations using a key to indicate which animations we are currently working on. So to inistansiate a sprite an key is set and a set of animations or a single frame loaded into the sprite:
/* Cursor */
baseCursor = new SiSEAnimation("cursor/CursInfo");
clearCursor = new SiSEAnimation("cursor/ClearCursInfo");
cursor = new SiSECursor(m_Window,250.0f,250.0f);
cursor->setAnimKey(CLEARKEY);
cursor->m_addAnimation(clearCursor);
cursor->setAnimKey(CURSKEY);
cursor->m_addAnimation(baseCursor);
Hope someone can help..:)
For anyone interested the Vector2D class is shown below:
#ifndef INCLUDE_VEC2D_H#define INCLUDE_VEC2D_Htypedef float SCALAR;class Vector2D{ public: Vector2D(); Vector2D(const SCALAR& a, const SCALAR& b); ~Vector2D(); SCALAR& operator[](const long i); const bool operator==(const Vector2D& v) const; const bool operator!=(const Vector2D& v) const; const Vector2D operator-(void) const; const Vector2D& operator=(const Vector2D& v); const Vector2D& operator+=(const Vector2D& v); const Vector2D& operator-=(const Vector2D& v); const Vector2D& operator*=(const SCALAR& s); const Vector2D& operator/=(const SCALAR& s); const Vector2D operator+(const Vector2D& v) const; const Vector2D operator-(const Vector2D& v) const; const Vector2D operator*(const SCALAR& s) const; friend inline const Vector2D operator* (const SCALAR& s, const Vector2D v){return v*s;} const Vector2D operator/(const SCALAR& s) const; const Vector2D perpen(void) const; const SCALAR dot(const Vector2D& v) const; const SCALAR length(void) const; const Vector2D unit(void) const; void normalise(void); const bool nearlyEquals(const Vector2D& v, const SCALAR e) const; void SetX(SCALAR xPos){x=xPos; calcMagnitude();} SCALAR GetX(void){return x;} void SetY(SCALAR yPos){y=yPos; calcMagnitude();} SCALAR GetY(void){return y;} void SetXY(SCALAR xPos, SCALAR yPos){x=xPos; y=yPos; calcMagnitude();} double GetMagSQRD(void){return magnitude;} private: void calcMagnitude(void); SCALAR x; SCALAR y; double magnitude;};typedef Vector2D POINT;#endif#include "SiSEVector2D.h"#include <cmath>Vector2D::Vector2D():x(0), y(0), magnitude(0.0){}Vector2D::Vector2D(const SCALAR& a, const SCALAR& b):x(a), y(b){ calcMagnitude();}Vector2D::~Vector2D(){}void Vector2D::calcMagnitude(void){ magnitude = (fabs(x*x)+fabs(y*y));}SCALAR& Vector2D::operator[](const long i){ return *((&x)+i);} const bool Vector2D::operator==(const Vector2D& v) const{ return (v.x==x && v.y==y);} const bool Vector2D::operator!=(const Vector2D& v) const{ return !(v==*this);}const Vector2D Vector2D::operator-(void) const{ return Vector2D(-x,-y);} const Vector2D& Vector2D::operator=(const Vector2D& v){ x=v.x; y=v.y; return *this;}const Vector2D& Vector2D::operator+=(const Vector2D& v){ x+=v.x; y+=v.y; return *this;}const Vector2D& Vector2D::operator-=(const Vector2D& v){ x-=v.x; y-=v.y; return *this;}const Vector2D& Vector2D::operator*=(const SCALAR& s){ x*=s; y*=s; return *this;}const Vector2D& Vector2D::operator/=(const SCALAR& s){ const SCALAR r = 1/s; x*=r; y*=r; return *this;}const Vector2D Vector2D::operator+(const Vector2D& v) const{ return Vector2D(x+v.x,x+v.y);} const Vector2D Vector2D::operator-(const Vector2D& v) const{ return Vector2D(x-v.x,y-v.y);}const Vector2D Vector2D::operator*(const SCALAR& s) const{ return Vector2D(x*s, y*s);}const Vector2D Vector2D::operator/(const SCALAR& s) const{ SCALAR t=1/s; return Vector2D(t*x,t*y);}const Vector2D Vector2D::perpen(void) const{ return Vector2D(this->y, -(this->x));}const SCALAR Vector2D::dot(const Vector2D& v) const{ return x*v.x + y*v.y;}const SCALAR Vector2D::length(void) const{ return (SCALAR)sqrt((double)this->dot(*this));}const Vector2D Vector2D::unit(void) const{ return (*this)/length();}void Vector2D::normalise(void){ (*this)/=length();}const bool Vector2D::nearlyEquals(const Vector2D& v, const SCALAR e) const{ return fabs(x-v.x)<e && fabs(y-v.y) < e;}
[Edited by - garyfletcher on May 23, 2005 1:45:49 AM]
Slightly unrelated, what sort of problems were you having with the mouse in fullscreen mode? I've had no problems with SDL in fullscreen with the mouse in my tests (both Windows and Linux).
It might be different under Linux but with windows cursor control isn't provided with SDL.
Not too sure why...think I read somewhere it's to do with problems with directly accessing hardware, but some cards provide support.
Although don't quote me on that..:)
Not too sure why...think I read somewhere it's to do with problems with directly accessing hardware, but some cards provide support.
Although don't quote me on that..:)
Okay I'm almost there.
I've now got a cursor on screen and moving and got mouse events being detected...hooray.
I have noticed though that when a mouse even is taking place, such as mouse motion, background rendering starts slowing down.
Is there anything that I can do to prevent this?
My code is now quite simple:
Any suggestions?
I've now got a cursor on screen and moving and got mouse events being detected...hooray.
I have noticed though that when a mouse even is taking place, such as mouse motion, background rendering starts slowing down.
Is there anything that I can do to prevent this?
My code is now quite simple:
void SiSECursor::mGetCursPos(){ SDL_Event event; button = NONPRESSED; if (SDL_PollEvent(&event)) { if (event.type == SDL_MOUSEMOTION ) { SDL_GetMouseState(&mouseAX,&mouseAY); } else if (event.type == SDL_MOUSEBUTTONDOWN ) { if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_LEFT)) { button = LPRESSED; } else if (SDL_GetMouseState(NULL,NULL)&SDL_BUTTON(SDL_BUTTON_RIGHT)) { button = RPRESSED; } } }}
Any suggestions?
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement