Creating a class once and passing it independently to other objects

I have a class called LoaderAnimation, which basically displays a sequence of 112 images when particles on the screen are hovered.

I was initially creating a loader animation inside a particle class, but every time I would create 25 particles it meant that 112 * 25 = 2800 images would be loaded on memory. Which is very inefficient.

The problem is that the loader animation has some logic when hovering and not hovering on the particles. If the user finishes the loader animation, it should trigger and action that reveals a menu. If the user hovers but doesn't finish the loader animation it should be reseted.

So here is the code for LoaderAnimation class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#pragma once

#include "ofMain.h"

class LoaderAnimation {    
    
public:
    
    LoaderAnimation();
    void setup();
    void update();
    void draw(float &_x, float &_y);
    
    vector <ofImage> loaderImages;
    bool hasPassedValue, isLoadingCompleted, bFrameIndependent;
    float rotationSpeed, sequenceFPS;
    int frameIndex, appFPS;
    unsigned int rotationCounter;
    
private:
    
    
};

#include "LoaderAnimation.h"

LoaderAnimation::LoaderAnimation(){
    
    
}
//-------------------------------------------------------------------
void LoaderAnimation::setup(){
    
    ofDirectory dir;
    
    int nFiles = dir.listDir("assets/9_loader");
    if(nFiles) {
        
        for(int i=0; i<dir.numFiles(); i++) {
            
            // add the image to the vector
            string filePath = dir.getPath(i);
            loaderImages.push_back(ofImage());
            loaderImages.back().loadImage(filePath);
            
        }
    } else printf("Could not find image loader #1's folder (in Boid class) \n");
    
    for(int i=0; i<loaderImages.size();i++){
        loaderImages[i].resize(loaderImages[i].width/2,loaderImages[i].height/2);
    }
    
    // this toggle will tell the loader sequence
    // to be indepent of the app fps
    bFrameIndependent = true;
    
    // this will set the speed to play the animation back.
    // we set the default to 24fps
    sequenceFPS = 0;
    
    frameIndex = 0;
    rotationCounter = 0;
    rotationSpeed = 1;
    isLoadingCompleted = false;
    
}
//-------------------------------------------------------------------
void LoaderAnimation::update(){
    
    if( rotationCounter == 1){ // if loadeded reset values
        
        //trigger post-load animation here
        frameIndex = 0;// we reset our frameIndex here
        
        
    }else if(rotationCounter == 0 && frameIndex < 112){ // if not, then we draw

        frameIndex += rotationSpeed;
        
        if(bFrameIndependent) { // calculate the frame index based on the app time
            // and the desired sequence fps. then mod to wrap
        } else { // set the frame index based on the app frame
            // count. then mod to wrap.
            frameIndex = ofGetFrameNum() % loaderImages.size();
        }
    }
    
    if(frameIndex >= 111){ // if we are over the particle and we finish loading we reset some values;
        
        rotationCounter = 1; // rotation counter is done!
        isLoadingCompleted = true;
        frameIndex = 0;
    }
    

}
//-------------------------------------------------------------------
void LoaderAnimation::draw(float &_x, float &_y){
    
    ofPushStyle();{
        ofPushMatrix();
        // draw the image sequence at the new frame count
        ofTranslate(0,0,100 );
            ofSetRectMode(OF_RECTMODE_CENTER);
            ofSetColor(255,255);
            loaderImages[frameIndex].draw( _x, _y, 1);
        
        ofPopMatrix();
    }ofPopStyle();
    
}


Pretty straight forward. setup() to load the images in my vector of images. update() to loop through the different images and draw() to display the images.

Now this is where the problem comes. In my particle class, I pass a pointer to the LoaderAnimation. But since multiple particles are being created through a controller class, whenever I work with the logic of the loaderAnimation doesn't work since all the particles are receiving the same pointer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void Boid::update(LoaderAnimation *_loader){

    _loader->update();

    switch (boidState) {
            
        case 0:// regular particle behavior

            _loader->frameIndex = 0;
            _loader->rotationCounter = 0;

            break;

           case 1: // hovering and loader
            
            
            pos = lastPos; // we stop the particle

            if( _loader->frameIndex >= 110){
                
                boidState = 2;
            }

            break;

}


As you can see, this code doesn't work because in my controller class when I hover in particle number 1 it does change the boidState to 2, but because the other particles are in boidState 1 and contain the same loader, it won't display my animation.

Is there any design pattern or copy method that allows me to use the same instance independently. I know this sounds weird but I'm just curious. I have been reading about the singleton pattern but don't quite understand it as the examples out there are all the same. I'm more than open to other algorithmic solutions for this problem.
Is there any design pattern or copy method that allows me to use the same instance independently?


Not that I know of. Unless otherwise you pass a copy of your LoadAnimation object to every instance of the particles. However, there's something I started thinking about, why not use the Observer pattern, such that every particle keep some housekeeping information about LoadAnimation's current state before any instance of the Particle class changes it?
@OxBADC0DE

Thanks for your reply. I was reading about the Observer pattern and I think it can work. I was looking at this example: http://www.codeproject.com/Articles/328365/Understanding-and-Implementing-Observer-Pattern.

An based on what you said:
started thinking about, why not use the Observer pattern, such that every particle keep some housekeeping information about LoadAnimation's current state before any instance of the Particle class changes it?


Shouldn't it be the other way around? Meaning, shouldn't the loader be aware of the state of the Boids so that it knows when to draw itself and in what Boid?

I think I understand the example, but I'm having a hard time scaling it to what I need specifically. How do I implement the pattern without initializing too many objects at the same time? In that link I sent you. How does it become efficient if you end up with 5000 shops? The subject will have to push 5000 instances to its vector <Shop *> list;

If you can provide a general outline at least at the pseudo code level that would be helpful.

Thanks again!
Last edited on
I figured it out. I think the observer pattern approach worked perfect here. So in my LoaderAnimation::update I pass two pointers of the particles that I need to check. So that when they are hovered I draw and then do my logic from there:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

void LoaderAnimation::update(FamiliesController *_tmp, vector <NotesController *> &_tmpNotes){
    
    mousePos.x = ofGetMouseX();
    mousePos.y = ofGetMouseY();
    
    
    if( _tmp->returnFamilySelected() == -1){// If a family hasn't been chosen, we update our family
        
        //---------------------- FAMILY UPDATE ----------------------//
        
        vector<bool>::iterator it;
        it = find(_tmp->isParticleHovered.begin(), _tmp->isParticleHovered.end(), true);
        if (it != _tmp->isParticleHovered.end()){// we look if a particle is being hovered.
            
            isHovered = true;// we use this to check internally
            
        }else{
            
            isHovered = false;
        }
        
        // ------------------- BOID STATE = 0 ------------------- //
        
        // we set our loader based on the hovering state
        if ( isHovered && loaderState == 0){// if we hover, we start showing the loader
            
            loaderState = 1;
            
        }else if( !isHovered && loaderState == 1){// otherwise we reset it.
            
            loaderState = 0;
        }
        
        for( int i = 0; i < _tmp->boidList.size() ; i ++){// we go into
            
            // ------------------- BOID STATE = 1 ------------------- //
            
            if (_tmp->boidList[i]->boidState == 1) {// we check if a particles
                
                pos = _tmp->boidList[i]->pos;// we pass the position at which we are drawing the loader.
                
                if ( loaderState == 2){// if the loader finish, we change the state of that particle
                    
                    _tmp->boidList[i]->boidState = 2;
                    //                    loaderState = 0;//we reset our loader
                }
            }
       }

           // ---------------- LOADER UPDATE --------------- //
    
    
    switch (loaderState) {
        case 0:// nothing is hovered we don't move.
            
            frameIndex = 0;
            pos = ofPoint(0,0);
            break;
            
        case 1:// we are hovering.
            
            frameIndex += rotationSpeed;
            
            if(bFrameIndependent) { // calculate the frame index based on the app time
                // and the desired sequence fps. then mod to wrap
            } else { // set the frame index based on the app frame
                // count. then mod to wrap.
                frameIndex = ofGetFrameNum() % loaderImages.size();
                
            }
            
            if (frameIndex > 110){//if we have loaded all the images, we move to the next state.
                
                loaderState = 2;
            }
            
            break;
            
        case 2:// we finish loading and reset.
            
            frameIndex = 0;
            loaderState = 0;
            pos = ofPoint(0,0);
            break;
            
        default:
            break;
    }
}


By using the loader as "the subject" I manages to keep track of where the loader needs to be drawn based on the status of my family and notes class.

Thanks for the suggestions!
Topic archived. No new replies allowed.