Calling a method in a parent - ofxSceneManager

Hi guys,

This is probably a super basic C++ question but I am trying to call a parent method from a child class. This is my structure.

-ofApp --ofxSceneManager ----scene1.h -----button.h ---scene2.h -----button.h

I want to call a changeScene() method that is part of ofxSceneManager (in ofApp) from button.h I tried calling it with a pointer as Arturo suggested in this post but I keep erroring out.

ofApp* app = dynamic_cast<ofApp*>(ofGetAppPtr()); app->sceneManager.changeScene(1);

Any help appreciated.

are you trying to do this in a .h file? you can have problems if ofApp.h include button.h and button.h includes ofApp.h (since includes are recursive). You can definitely include ofApp.h in a .cpp file (such as button.cpp) and then use the ofGetAppPtr().

Thanks Zach. Ive tried including ofApp.h to button.cpp and it errors out pretty hard. Here is some code… I must be doing something else wrong… structure is ofApp > levelone / leveltwo (left out) > button. Also, the ofLog() in button.cpp prints fine so the button works … thank you.

ofApp.h

#include "ofxiOS.h"
#include "ofxSceneManager.h"

class ofApp : public ofxiOSApp {
	
    public:
        void setup();
        void update();
        void draw();
        void exit();
        void changescene();
        ofxSceneManager sceneManager;

};

ofApp.mm

#include "ofApp.h"

#include "levelone.h"
#include "leveltwo.h"

//--------------------------------------------------------------
void ofApp::setup(){
    
    sceneManager.addScene(ofPtr<ofxScene>(new levelone));
    sceneManager.addScene(ofPtr<ofxScene>(new leveltwo));
    sceneManager.setExitByTime(true);
    sceneManager.setSceneDuration(0.4, 0.6, 0.4);
    sceneManager.setTransitionFade();
    sceneManager.run();
}

//--------------------------------------------------------------
void ofApp::update(){
    sceneManager.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofBackground(0, 0, 0);
    sceneManager.draw();
}

//--------------------------------------------------------------
void ofApp::exit(){
}
//--------------------------------------------------------------
void ofApp::changescene(){
    sceneManager.changeScene(1);
}

levelone.h

#ifndef _levelone_
#define _levelone_

#include "ofxScene.h"
#include "button.h"

class levelone : public ofxScene {
public:
    
    levelone();
    
    void setup();
    void update();
    void draw();
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    
    int y = 0;
    
    button buttontest;
};

#endif

levelone.cpp

#include "levelone.h"

//------------------------------------------------
levelone::levelone(){
}

//------------------------------------------------
void levelone::setup() {
}

//------------------------------------------------

void levelone::update() {
}

//------------------------------------------------

void levelone::draw() {
    
    //bgcolor
    ofSetHexColor(0x00BCD4);
    ofRect(0, 0, ofGetWidth(), ofGetHeight());
    
    //moving line
    ofSetHexColor(0x0097A7);
    y = (y+2) % ofGetHeight();
    ofRect(0, y, ofGetWidth(), 10);
    
    //button
    buttontest.draw(10, ofGetHeight()-50, ofGetWidth()-20, 40, 0x727272);
}

//------------------------------------------------
void levelone::mousePressed(int tx, int ty, int button){
    buttontest.touch(tx, ty);
}

//------------------------------------------------
void levelone::mouseReleased(int tx, int ty, int button){
}

button.h

#ifndef _button_
#define _button_

#include "ofMain.h"

class button{
    
public:
    
    void setup();
    void update();
    void draw(int x, int y, int width, int height, int color);
    void enable();
    void disable();
    void touch(int tx, int ty);
    void up();
    bool hittest(int tx, int ty);

};

#endif

button.cpp

#include "button.h"
#include "ofApp.h" //<<<<<<<<<<<<< THIS ERRORS

int butx;
int buty;
int butwidth;
int butheight;

//------------------------------------------------

void button::setup() {
}

//------------------------------------------------

void button::enable() {
}

//------------------------------------------------

void button::disable() {
}

//------------------------------------------------

void button::update(){
}

//------------------------------------------------

void button::draw(int x, int y, int width, int height, int color){
    
    butx = x;
    buty = y;
    butwidth = width;
    butheight = height;
    
    ofSetHexColor(color);
    ofRect(x, y, width, height);
}

//------------------------------------------------

void button::touch(int tx, int ty){
    
    if(hittest(tx, ty)) {
        ofLog() << "Button Tapped!";
        //<<<<<<<<<<<<<<<<<<<<<< HERE
        //ofApp* app = dynamic_cast<ofApp*>(ofGetAppPtr());
       //app->sceneManager.changeScene(1)
    }
    
}

//------------------------------------------------
void button::up(){
}

//------------------------------------------------

bool button::hittest(int tx, int ty){
    return ((tx > butx) && (tx < butx + butwidth) && (ty > buty) && (ty < buty + butheight));
}

//------------------------------------------------

Here’s a pattern I’ve been using by emitting ofEvents so that the sending & receiving classes don’t have to know about each other (avoiding issues of recursive header includes mentioned above, using or needing to cast ofGetAppPtr(), etc.)

create an Events.h file with the events you want:

#pragma once

#include "ofEvents.h"

class Events {
public:

    ofEvent<int> changeToScene;

    static Events& get() {
        static Events instance;
        return instance;
    }
};

From places you want to see change the scene from (i.e. your button classes), add #include "Events.h" to your header. To change the scene from the button cpp file:

void button::touch(int tx, int ty){  
	if (hittest(tx, ty)) {
		ofLog() << "Button Tapped!";
		int newSceneId = 1; // 
		ofNotifyEvent(Events::get().changeToScene, newSceneId);
	}
}

Note that because of how ofEvent arguments work, you need to create a variable with your argument value and pass it in – you can’t pass the int directly like this: ofNotifyEvent(Events::get().changeToScene, 1);

Then, in ofApp, you’ll want to receive that event and call changeScene() on the ofxSceneManager instance. So add the Events.h include to ofApp.h, and declare a callback for when the event gets called:

#include "ofMain.h"
#include "Events.h"

class ofApp() {
public:
	void setup();
	void update();
	void draw();
	void changeToScene(int& newSceneId); // new callback
}

Then in ofApp.cpp you can register for the callback in setup() and finally define the callback:

ofApp::setup() {
	ofAddListener(Events::get().changeToScene, this, &ofApp::changeToScene)
}

void ofApp::changeToScene(int& newSceneId) {
	scene.changeTo(int);
}

Hope that helps! (and hope it works…I copy/pasted from another project so there might be an error somewhere)

3 Likes

@mattfelsen this is amazing and worked perfectly! A bunch of noob questions…

Why is the event code in the .h file? Could I have put it in a .cpp?
Can I create more vars/events in the same file exactly like this but with a different name?
Are there any best practices on when to use events vs pointers?
What is the & in static events& get() doing exactly?

Thank you so much for your help. This forum is the best.

Thanks @mattfelsen ! I’ve tried zach’s approach before but ofEvent is one of the black magic I’m not familiar with. This looks super simple to use.

@andehlu I found this gist that is very helpful to understand how ofEvent works. I also put it on github here. Also read important note on the documentation about unregistering event in destruction of the listener.

2 Likes

Glad it worked! Yes you could move the Events::get() definition into the cpp but since it’s the only function in that class (the bulk of it would be declarations of additional ofEvents that you want to use) so I just put it into the h for convenience and to simplify not needing a cpp file.

And yes, you can add as many different ofEvents as you’d like, with any type the you want to pass along.

Generally if I am doing something other than calling a method directly on a parent or child class, or if I want to make something happen in a separate part of that app, especially when the classes don’t need to know about the existence or function of a another class, I’ll use an ofEvent.

The Events class uses the singleton pattern, and the get() method returns the singleton instance. Here’s some info: http://stackoverflow.com/questions/1463707/c-singleton-vs-global-static-object

1 Like