Menu

modifying a class variable

Musa
2009-01-02
2012-09-26
  • Musa

    Musa - 2009-01-02

    I am trying to modify the variable "done" from the class "Explosion" through the "sequenceEnded" function(see classes below)
    The problem is after "sequenceEnded", "ifDone()" still returns false.
    "sequenceEnded" is called from "updateTick()" in the "ImagesPlayer" class
    "ifDone()" is called from the "drawSprite" method in the "Meteor" class from an iterator.
    I'm now learning C++ so I might be making a silly mistake or maybe not i don't know.

    include <string>

    using namespace std;
    class ImagesPlayerWatcher
    {
    public:
    virtual void sequenceEnded(string imageName) =0;
    };

    class Explosion: public Sprite, public ImagesPlayerWatcher{
    bool done;
    public:
    Explosion (int x, int y, int pw, int ph, ImagesManager* il):Sprite(x, y, pw, ph, il, "explosion"){
    done = false;
    Sprite::setStep(0, 0);
    player.setWatcher(this);
    Sprite::playImage(33);
    }
    bool ifDone(){return done;}
    void sequenceEnded(string imageName){
    done = true;
    }
    };

    class Meteor: public Sprite{
    list<Explosion> explosions;
    list<Shot> shots;
    Sprite
    ship;
    public:
    Meteor (int x, int y, int pw, int ph, ImagesManager il, string s, list<Shot> shots, Sprite ship):Sprite(x, y, pw, ph, il, s){
    this->shots = shots;
    this->ship = ship;
    }
    bool intersect(Rectangle rec){
    bool result = false;
    Rectangle bdrec = getMyRectangle();
    if ((bdrec->x <= rec->x)&&(bdrec->x+bdrec->w >= rec->x)&&(rec->y <= bdrec->y+bdrec->h)&&(rec->y+rec->h > bdrec->y)){
    explosions.push_back(Explosion(rec->x, rec->y, 480, 272, imsLoader));
    result = true;
    }
    else if ((rec->x <= bdrec->x)&&(rec->x+rec->w >= bdrec->x)&&(bdrec->y <= rec->y+rec->h)&&(bdrec->y+bdrec->h > rec->y)){
    explosions.push_back(Explosion(rec->x, rec->y, 480, 272, imsLoader));
    result = true;
    }
    delete rec;
    delete bdrec;
    return result;
    }
    bool blownUp(){
    list<Shot>::iterator it = shots->begin();
    for (; it != shots->end(); it++){
    if (intersect((
    it).getMyRectangle())){
    shots->erase(it);
    return true;
    }
    }
    if (intersect(ship->getMyRectangle()))
    return true;
    return false;
    }
    void updateSprite(){
    Sprite::updateSprite();
    if ((locx < 0)||(blownUp())){
    locx = 480;
    }
    list<Explosion>::iterator it = explosions.begin();
    for (; it != explosions.end(); it++)
    (*it).updateSprite();
    }
    void drawSprite(Image screen){
    Sprite::drawSprite(screen);
    list<Explosion>::iterator it = explosions.begin();
    for (; it != explosions.end(); it++){
    it->drawSprite(screen);
    cout << explosions.size() <<"\n";
    if (it->ifDone()){
    cout << "to erase\n";
    it = explosions.erase(it);
    }

           }
      }
    

    };

    class ImagesPlayer
    {
    string imName;
    bool isRepeating, ticksIgnored;
    ImagesManager *imsLoader;

      int animPeriod;
         // period used by animation loop (in ms)
      unsigned long animTotalTime;
    
      unsigned long animLastTime;
    
      int showPeriod;     
         // period the current image is shown (in ms)
      unsigned long seqDuration;   
         // total duration of the entire image sequence (in secs)
    
      int numImages;
      int imPosition;     // position of current displayable image
    
      ImagesPlayerWatcher *watcher;
    
      void _ImagesPlayer(string , int , bool , ImagesManager* );
    

    public:
    ImagesPlayer(){};
    ImagesPlayer(string s, int i, bool b, ImagesManager* im){
    _ImagesPlayer(s, i, b, im);
    }

      void modify(string s, int i, bool b, ImagesManager *im){
           _ImagesPlayer(s, i, b, im);
      }
    
      void updateTick();
    
      int getCurrentImage();
    
      int getCurrentPosition(){  return imPosition;  };
    
      void setWatcher(ImagesPlayerWatcher* w){  watcher = w;  };
    

    / updateTick() calls will no longer update the
    total animation time or imPosition.
    /
    void stop(){ ticksIgnored = true; };

      bool isStopped(){  return ticksIgnored;  };
    

    // are we at the last image and not cycling through them?
    bool atSequenceEnd(){ return ((imPosition == numImages-1) && (!isRepeating)); };

      void restartAt(int );
    
      void resume()
    

    // start at previous image position
    {
    if (numImages != 0)
    ticksIgnored = false;
    };
    }; // end of ImagesPlayer class

    void ImagesPlayer::_ImagesPlayer(string nm, int ap, bool isr, ImagesManager il)
    {cout << "ImagesPlayer\n";
    imName = nm;
    animPeriod = ap;
    seqDuration = animPeriod
    il->numImages(imName);
    isRepeating = isr;
    imsLoader = il;

    animTotalTime = 0L;
    struct timeval tv;
    sceKernelLibcGettimeofday(&amp;tv, NULL);
    animLastTime = tv.tv_sec*1000 + tv.tv_usec/1000;
    if (!imsLoader-&gt;isLoaded(imName)) {
      cout &lt;&lt; imName &lt;&lt; &quot; is not known by the ImagesLoader&quot; &lt;&lt; endl;
      numImages = 0;
      imPosition = -1;
      ticksIgnored = true;
    }
    else {
      numImages = imsLoader-&gt;numImages(imName);
      imPosition = 0;
      ticksIgnored = false;
    }
    

    } // end of ImagesPlayer()

    void ImagesPlayer::updateTick()
    / We assume that this method is called every animPeriod ms /
    {
    if (!ticksIgnored) {
    // update total animation time, modulo the animation sequence duration
    struct timeval tv;
    sceKernelLibcGettimeofday(&tv, NULL);
    int animTime = tv.tv_sec*1000 + tv.tv_usec/1000;

      animTotalTime = (animTotalTime + (animTime - animLastTime)) % seqDuration;
      animLastTime = animTime;
      // calculate current displayable image position
      imPosition = (int) (animTotalTime / animPeriod);   // in range 0 to num-1
      if ((imPosition == numImages-1) &amp;&amp; (!isRepeating)) {  // at end of sequence
        ticksIgnored = true;   // stop at this image
        if (watcher != NULL)
          watcher-&gt;sequenceEnded(imName);   // call callback
      }
    }
    

    } // end of updateTick()

    int ImagesPlayer::getCurrentImage()
    { if (numImages != 0)
    return imPosition;
    return 0;
    } // end of getCurrentImage()

    void ImagesPlayer::restartAt(int imPosn)
    / Start showing the images again, starting with image number
    imPosn. This requires a resetting of the animation time as
    well.
    /
    {
    if (numImages != 0) {
    if ((imPosn < 0) || (imPosn > numImages-1)) {
    cout << "Out of range restart, starting at 0";
    imPosn = 0;
    }

      imPosition = imPosn;
      // calculate a suitable animation time
      animTotalTime = (long) imPosition * animPeriod;
      ticksIgnored = false;
    }
    

    } // end of restartAt()

     
    • matik

      matik - 2009-01-03

      well, the program is long and i guess no-one will debug it for you. you have to start debugging self.

      i suggest maybe add to "sequenceEnded" method something like:
      cout << "sequenceEnded called!" << endl;

      and see where it goes. maybe its not called on right objects. log the object (this) ptr also etc

       
    • cpns

      cpns - 2009-01-03

      Your code fragment does not include a call to updateTick(), so we have to assume that when you call ifDone(), updateTick() was never called. From that fragment more than that we cannot tell.

      Either way you look it at it we only have your word for it, and it is not plausible on lack of evidence presented.

      I suggest that you learn to use the debugger (actually I suggest you use a different tool with a working and usable debugger!).

      Clifford

       
    • Musa

      Musa - 2009-01-03

      So my word isn't good enough ;)
      I missed out the Sprite class, updateTick is called from updateSprite
      I was thinking the problem was with sub-classing an abstract class(ImagesPlayer) or modifying a class variable in the (defined)abstract method but thats not the case since I changed ImagesPlayer from abstract and it still didn't work.
      @matic: I did that, thats how i know "sequenceEnded" is called
      also isn't "this" a ptr to the instance of the class itself, so how could it be wrong.

      class Sprite
      {
      // default step sizes (how far to move in each update)
      static const int XSTEP = 0;
      static const int YSTEP = 0;

      // default dimensions when there is no image
      static const int SIZE = 12;

      // image-related
      string imageName;
      Image image;
      int width, height; // image dimensions

        bool isPlaying;
      
        int pWidth, pHeight;   // panel dimensions
      

      // a sprite is updated and drawn only when it is active

      // protected vars
      protected:
      int locx, locy; // location of sprite
      int dx, dy; // amount to move for each update
      ImagesPlayer player; // for playing a loop of images
      ImagesManager *imsLoader;
      bool isActive_;

      public:
      Sprite(int , int , int , int , ImagesManager* , string );

        void setImage(string );
      
        void playImage(int );
      
        void loopImage(int );
      
        void stopLooping();
        // of the sprite's image
        int getWidth(){  return imsLoader-&gt;getWidth(imageName);  }
        // of the sprite's image
        int getHeight(){  return imsLoader-&gt;getHeight(imageName);  }
        // of the enclosing panel
        int getPWidth(){  return pWidth;  }
        // of the enclosing panel
        int getPHeight(){  return pHeight;  }
      
        bool isActive(){  return isActive_;  }
      
        void setActive(bool a){  isActive_ = a;  }
      
        void setPosition(int x, int y){  locx = x; locy = y;  }
      
        void translate(int xDist, int yDist){  locx += xDist;  locy += yDist;  }
      
        int getXPosn(){  return locx;  }
      
        int getYPosn(){  return locy;  }
      
        void setStep(int dx, int dy){  this-&gt;dx = dx; this-&gt;dy = dy; }
      
        int getXStep(){  return dx;  }
      
        int getYStep(){  return dy;  }
      
        Rectangle getMyRectangle()
        { Rectangle rect = new SDL_Rect; 
          rect-&gt;x = locx;
          rect-&gt;y = locy;
          rect-&gt;w = getWidth();
          rect-&gt;h = getHeight();
          return rect;
        }
      
        void updateSprite();
      
        void drawSprite(Image );
      

      }; // end of Sprite class
      Sprite::Sprite(int x, int y, int w, int h, ImagesManager *imsLd, string name)
      {
      isActive_ = true;
      locx = x; locy = y;
      pWidth = w; pHeight = h;
      dx = XSTEP; dy = YSTEP;

      imsLoader = imsLd;
      setImage(name);    // the sprite's default image is 'name'
      

      } // end of Sprite()

      void Sprite::setImage(string name)
      // assign the name image to the sprite
      {
      imageName = name;
      / image = imsLoader.getImage(imageName);
      if (image == NULL) { // no image of that name was found
      cout << "No sprite image for " << imageName << endl;
      width = SIZE;
      height = SIZE;
      }
      else {
      width = image->w;
      height = image->h;
      }
      /
      // no image loop playing
      //player~ImagesPlayer();
      isPlaying = false;
      } // end of setImage()

      void Sprite::playImage(int animPeriod)
      / Switch on loop playing. The total time for the loop is
      seqDuration secs. The update interval (from the enclosing
      panel) is animPeriod ms.
      /
      {
      if (imsLoader->numImages(imageName) > 1) {
      player.modify(imageName, animPeriod, false, imsLoader);
      isPlaying = true;
      }
      else
      cout << imageName << " is not a sequence of images" << endl;
      } // end of loopImage()

      void Sprite::loopImage(int animPeriod)
      / Switch on loop playing. The total time for the loop is
      seqDuration secs. The update interval (from the enclosing
      panel) is animPeriod ms.
      /
      {
      if (imsLoader->numImages(imageName) > 1) {
      player.modify(imageName, animPeriod, true, imsLoader);
      isPlaying = true;
      }
      else
      cout << imageName << " is not a sequence of images" << endl;
      } // end of loopImage()

      void Sprite::stopLooping()
      {
      if (isPlaying) {
      player.stop();
      isPlaying = false;
      }
      } // end of stopLooping()

      void Sprite::updateSprite()
      // move the sprite
      {
      if (isActive()) {
      locx += dx;
      locy += dy;
      if (isPlaying)
      player.updateTick(); // update the player
      }
      } // end of updateSprite()

      void Sprite::drawSprite(Image s)
      {
      int index = 0;
      if (isActive()) {
      if (isPlaying)
      index = player.getCurrentImage();
      imsLoader->drawImage(s, imageName, locx, locy, index);

      }
      

      } // end of drawSprite()

       
    • cpns

      cpns - 2009-01-04

      > So my word isn't good enough ;)

      Well you told us how it works, but it doesn't work, so no. ;-)

      Now you have added code to show where updateTick() is called, but not enough to demonstrate that it is actually called or how or when. We cannot see updateSprite() being called. My point is that we need to see where, when and how these functions are called, and specifically the sequence between updateTick() and ifEnded()

      Matik is probably right, no one is going to take the trouble wade through all that code, especially since it is incomplete and highly likely that the problem exists elsewhere, or is contributed to by code not shown.

      In essence unless you post sufficient code to allow us to compile, link and debug it, you are probably not going to get very far. Usually when you post that much code without being able to compile it, well meaning people will start picking on the flaws they can see rather than teh one you want addressing. With that much code there is bound to be something someone does not like but which is irellevant to the problem in hand.

      I appreciate that you might not want to post all your code, a) because it is yours, and b) because there is probably a lot of it. However I suggest that had you done so, I would have placed a break point at done = true, and one on ifEnded(), and executed the code to see not only that both occur, but that the occur in the expected order. As I suggested however, the Dev-C++ debugger is worse than useless, so I'd be using a different tool with a better debugger.

      Is this code multi-threaded? If it is and done is set in one thread and read in another, remember to declare done volatile.

      Clifford

       
    • Musa

      Musa - 2009-01-04

      >maybe its not called on right objects. log the object (this) ptr also etc
      matik was right, in one object sequenceEnded was called and then in another ifDone.
      The problem is right here
      explosions.push_back(Explosion(rec->x, rec->y, 480, 272, imsLoader));
      apparently push_back stores a copy of object and not the object itself, is that how it suppose to be or am i doing something wrong?

       
    • Musa

      Musa - 2009-01-04

      Okay, I just read up on std::list and that is how it suppose to be. I want to know if you could make your own allocator so that you will just store the object and not a copy.
      If not... Anyway will the original Explosion object be destroyed when the function that calls explosions.push_back(Explosion(rec->x, rec->y, 480, 272, imsLoader)); exits? or do I have to do it explicitly.

       
      • cpns

        cpns - 2009-01-05

        > I want to know if you could make your own allocator so
        > that you will just store the object and not a copy.

        That is easily achieved by by creating a std::list of pointers to objects. You then simply place &object rather than object onto the list.

        > Anyway will the original Explosion object be destroyed when the function
        > that calls explosions.push_back(Explosion(rec->x, rec->y, 480, 272, imsLoader));
        > exits?

        It will be destroyed as soon immediately after the push_back(); it is a temporary object, not a scoped variable. Place a break point in the destructor to see when precisely this happens. However if you are going to use a list of pointers, the object must not be destroyed at all, which means instantiating it with the 'new' operator. It would be destroyed using 'delete' when the list is 'unpacked' (usually best done in the destructor of the class that contains the list).

        Clifford

         
    • Musa

      Musa - 2009-01-05

      okay thanks

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.