void TutorialApp::update() { /* * An event handler is a good place to add functionality * to your UiTree. Think of it as a many application for * your node. In this case, we've added some logic to the * event handler to record the ID of any node that needs * to be removed. */ uint64_t removeId = mEventHandler.getRemoveId(); /* * When removing a node, be sure to also remove any * external data it is using to save on resources. */ if ( removeId > 0 && mUiTree.removeChild( removeId ) ) { if ( mIdBatchMap.find( removeId ) != mIdBatchMap.end() ) { mIdBatchMap.erase( removeId ); } makeNode(); } mEventHandler.setRemoveId( 0 ); const float e = (float)getElapsedSeconds(); /* * If you ever need a flat list of all nodes in your UiTree, * run a query which returns true. */ list<UiTree*> nodes = mUiTree.query( []( const UiTree& node ) { return true; } ); const vec2 c = getWindowCenter(); /* * Although there is an update event in the UiTree, it is * best to keep the quantity of update signals to a minimum. * If you want to organize your code a bit, consider writing * "controller" nodes. That is, create a node's event handler * with some more sophisticated callbacks. If you have hundreds * or thousands of nodes that all have update or mouse events, * for example, you might get better performance by hit testing * them all from a single node instead of giving them all * their own event handlers. In this example, we update the tree * from the main application's update loop. */ for ( UiTree* a : nodes ) { if ( a->getParent() != nullptr ) { UiData& data = a->getData(); const float s = data.getSpeed(); a->setTranslate( c + vec2( cos( e * s ), sin( e * s ) ) * data.getDistance() ); float d0 = numeric_limits<float>::max(); for ( UiTree* b : nodes ) { if ( a != b && b->getScale().x > a->getScale().x ) { const float d1 = glm::distance( a->getTranslate(), b->getTranslate() ); if ( d1 < d0 ) { d0 = d1; a->setParent( b ); } } } } } }