In cocos2d-x, how can I display the bounding box for all sprites that are children of this layer?
Here's my starting point:
void MyLayer::draw()
{
// super draw
CCLayer::draw();
// Iterate through all nodes of this layer
for ( CCNode* node = ??? )
{
// Make sure the node is a CCSprite
if ( node == CCSprite ??? )
{
CCSprite* sprite = (CCSprite*) node;
ccDrawRect( sprite->boundingBox() ??? );
}
}
}
//put this line at the top of your cpp file
#define CC_VERIFY_TYPE(__OBJECT__,__CLASS_TYPE__) assert(dynamic_cast<__CLASS_TYPE__>(__OBJECT__))
//these lines in your code
CCObject* child;
CCARRAY_FOREACH(m_pChildren, child)
{
CC_VERIFY_TYPE(child,CCSprite*);
CCSprite* sprite = (CCSprite*) child;
CCSize s = sprite->boundingBox().size;
ccDrawRect(sprite->boundingBox().origin, ccpAdd(sprite->boundingBox().origin, (ccp(s.width,s.height))));
}
As you create all sprites in this layer by your own, you can, for example, create simple node, that will draw bounding box of its parent. Then just add instance of this node to any node/sprite you want to see.
Another way is to add all sprites/nodes you want to see in additional array and draw bounding box of each object in this array.
Related
I have a scene and inside the scene I have the ellipses (circles) to which I change the position with setPos() so when I ask for its position later I will not get 0,0 coordinates, but now when I want to delete the object, the member function contains() does not ever evaluate to true understandably. The question is, how can I get to the scene coordinates or object coordinates so when I click on the object I get the true evaluation of contains() member function. I have tried the mapToScene(), mapFromScene() which do not help. (still kinda lost in Qt coordinate system)
Code sample:
void MyQGraphicsView::mousePressEvent(QMouseEvent * e)
{
QPointF pt = mapToScene(e->pos());
if(e->button()==Qt::RightButton)
{
// remove point
QList<QGraphicsItem *> listIt = scene->items();
QList<QGraphicsItem *>::const_iterator stlIter;
QGraphicsItem * itemToRemove = NULL;
QGraphicsEllipseItem it; // for type checking
for(stlIter = listIt.begin(); stlIter != listIt.end(); ++stlIter)
{
// if it has the expected type and the point is inside (type checking is redundant)
if(((*stlIter)->type() == it.type()) && ((*stlIter)->contains(pt))){
// contains(pt) is never true - understandably
itemToRemove = *stlIter;
break;
}
}
if(itemToRemove != NULL) scene->removeItem(itemToRemove);
}else{ // leftClick to add ellipse
double rad = 10;
QGraphicsEllipseItem* pEllipse = scene->addEllipse(-rad, -rad, rad*2.0, rad*2.0, QPen(Qt::red,0), QBrush(Qt::red,Qt::SolidPattern));
pEllipse->setPos(pt.x(), pt.y()); // set the postion so it does not return 0,0
}
}
The QGraphicsItem::contains method takes points in local coordinates, that is in coordinates with (0, 0) being the center of the QGraphicsItem.
You are using points in global scene coordinates.
To get a point in local coordinates of a given QGprahicsItem you can use the QGraphicsItem::mapFromScene(const QPointF & point) method.
You might want to do something like :
for(Object& obj : objects)
if(obj.contains(obj.mapFromScene(point)))
// do stuf because point is inside obj
Sources :
http://doc.qt.io/qt-4.8/graphicsview.html#item-coordinates
http://doc.qt.io/qt-4.8/qgraphicsitem.html#contains
Using cocos2d, I'm trying to replace a sprite (item in my code) with a particle system. This code is placed in my board class. This one works:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = ccpSub(item.position,ccp(160,160));
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
This one doesn't:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = item.position;
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
I tried player with this but without success:
particles.positionType = CCPositionTypeMake(CCPositionUnitUIPoints, CCPositionUnitUIPoints, CCPositionReferenceCornerBottomLeft);
My board is a 320x320 points CCSprite with anchor point set at 0.5, 0.5
When I log my item.position value, I get something relative to the bottom left corner of my board (from 30,30 to 290,290)
Is using ccpSub the correct way ?
When you destroy a node you also destroy all of it's children nodes, you said you add your particle to 'item' then you destroy that 'item', which means you have no particle anymore.
i am new to ogre and have read the basic tutorials but unable to understand how to create a orbit camera with mouse wheel zooming.
here is my camera code
// Create the scene node(orbit camera)
node = mSceneMgr->getRootSceneNode()->createChildSceneNode("orbit", Ogre::Vector3(0, 100, -150));
node->attachObject(mCamera);
// create the second camera node(freecam)
node = mSceneMgr->getRootSceneNode()->createChildSceneNode("free", Ogre::Vector3(0, 100, 400));
// create the third camera node (3rd person robot cam)
node = mSceneMgr->getRootSceneNode()->createChildSceneNode("robocam", Ogre::Vector3(0, 100, -80));
And here is my keypress function
bool BasicTutorial05::processUnbufferedInput(const Ogre::FrameEvent& evt)
{
Ogre::Vector3 transVector1 = Ogre::Vector3::ZERO;
if (cam1 == true)//when cam 1 is selected, bool cam1 will be true;
{
if (mKeyboard->isKeyDown(OIS::KC_S))
{
mSceneMgr->getSceneNode("orbit")->pitch(Ogre::Radian(-0.012f));
}
if (mKeyboard->isKeyDown(OIS::KC_W))
{
mSceneMgr->getSceneNode("orbit")->pitch(Ogre::Radian(0.012f));
}
if (mKeyboard->isKeyDown(OIS::KC_A))
{
mSceneMgr->getSceneNode("orbit")->yaw(Ogre::Radian(0.012f));
}
if (mKeyboard->isKeyDown(OIS::KC_D))
{
mSceneMgr->getSceneNode("orbit")->yaw(Ogre::Radian(-0.012f));
}
}
mSceneMgr->getSceneNode("orbit")->translate(transVector1 *evt.timeSinceLastFrame, Ogre::Node::TS_LOCAL);
}
and the mouse wheel zooming
//zooming for orbit camera
Ogre::Vector3 transVector2 = Ogre::Vector3::ZERO;
if (mMouse->getMouseState().Z.rel != 0){
transVector2.z = -mMouse->getMouseState().Z.rel;
}
but i can able to sort of orbit around the point where the camera is but only when i use the wheel scroll zoom, instead of rotating around a point it rotates where the camera is.
How do i change it that it only rotates at a point?
Create two nodes for your camera - the first one is the target and it's placed at the point you want to rotate around.
The second node should be created at some distance from the first one. You should attach it as the child of the target and attach your camera to this node. Finally, you should point your camera at the target node (the first one).
With this setup you'll just need to put your target node at the point of your interest and rotate it as you want. The camera position will follow the target, because it's his child. And by moving your camera node closer to the target node you can change your zoom level.
I try to clone a CCNode hierarchy, the problems is I need to reset and set all the variable by type, can I have a way to do that more automatically ?
basiclly what I want to do is :
- store a CCNode* (with some child, for example an image at Pos 10-10, and a Label at Pos 100-50 with the text "Test");
- then clone it, for get a new CCNode* with the same default value and childs.
I need to copy it, because after they will get modify, is like a template of Node, before get custom value.
If you know a simple way to copy, and set all the hierarchy (with correct type also), without big if/else statement for each kind of type, it will help me a lot ^^
thanks
This code clones CCNode and all child CCNodes recursively. You can add other subclasses and other properties to copy.
+ (CCNode*) cloneCCNode:(CCNode*)source
{
CCNode* clone = [CCNode node];
for (CCNode* srcSubnode in source.children) {
CCNode* subnode;
if ([srcSubnode isKindOfClass:[CCSprite class]]) { //only CCSprites are copied, add other subclasses if you need to
CCSprite* srcSprite = (CCSprite*)srcSubnode;
subnode = [CCSprite spriteWithTexture:srcSprite.texture];
((CCSprite*)subnode).displayFrame = srcSprite.displayFrame;
} else {
subnode = [self cloneCCNode:srcSubnode];
}
subnode.rotation = srcSubnode.rotation;
subnode.position = srcSubnode.position;
subnode.anchorPoint = srcSubnode.anchorPoint;
subnode.zOrder = srcSubnode.zOrder;
[clone addChild:subnode];
}
return clone;
}
I am going to do pan/scale stuff on QGraphicsView.
So I read the documentation of QGraphicsView and see some utility functions like ensureVisible() and centerOn().
I think I understand what the documentation says but I can' t manage to write a working example.
Could you please write/suggest me an example code to understand the issue.
Ton pan the view by a certain amount (for example in your view's mouseMoveEvent()), assuming MyView is a subclass of QGraphicsView (all the following code was ported from Python, I didn't test it):
void MyView::moveBy(QPoint &delta)
{
QScrollBar *horiz_scroll = horizontalScrollBar();
QScrollBar *vert_scroll = verticalScrollBar();
horiz_scroll->setValue(horiz_scroll.value() - delta.x());
vert_scroll->setValue(vert_scroll.value() - delta.y());
}
To fit a rectangle specified in scene coordinates by zooming and panning:
void MyView::fit(QRectF &rect)
{
setSceneRect(rect);
fitInView(rect, Qt::KeepAspectRatio);
}
Note that if your scene contains non transformable items (with the QGraphicsItem::ItemIgnoresTransformations flag set), you'll have to take extra steps to compute their correct bounding box:
/**
* Compute the bounding box of an item in scene space, handling non
* transformable items.
*/
QRectF sceneBbox(QGraphicsItem *item, QGraphicsItemView *view=NULL)
{
QRectF bbox = item->boundingRect();
QTransform vp_trans, item_to_vp_trans;
if (!(item->flags() & QGraphicsItem::ItemIgnoresTransformations)) {
// Normal item, simply map its bounding box to scene space
bbox = item->mapRectToScene(bbox);
} else {
// Item with the ItemIgnoresTransformations flag, need to compute its
// bounding box with deviceTransform()
if (view) {
vp_trans = view->viewportTransform();
} else {
vp_trans = QTransform();
}
item_to_vp_trans = item->deviceTransform(vp_trans);
// Map bbox to viewport space
bbox = item_to_vp_trans.mapRect(bbox);
// Map bbox back to scene space
bbox = vp_trans.inverted().mapRect(bbox);
}
return bbox;
}
In that case the bounding rect of your objects becomes dependent on the view's zoom level, meaning that sometimes MyView::fit() won't fit exactly your objects (for example when fitting a selection of objects from a largely zoomed out view). A quick and dirty solution is to call MyView::fit() repeatedly until the bounding rect naturally "stabilizes" itself.