How to detect touches on child sprites - graphics

I'm writing a cocos2d-x application. I have a sprite with a couple of child sprites over it. These sprites represent one logical object on the screen that is transformed as a whole object. Now, when the object is touched, I need to discover which of the child sprites was touched.
The problem is that, while the parent sprite gives me all the information (bounding box, scale, rotation etc.) as it currently is, the child sprites stay with their original numbers, despite being transformed together with the parent, and I cannot figure out the correct way to calculate the "real" dimensions for the children.
As it looks to me, two facts cause all the difficulties:
The child bounding box has its initial dimensions which are reported relative to the parent's initial bounding box.
I cannot calculate the parent's initial bounding box after the parent was rotated (see the picture below), thus I cannot calculate where now is the lower left corner of the parent sprite, which I need as the relation point for child transformations.
Here's a drawing of such a situation:
So, to summarize, in order to check whether a touch hit a child sprite, I need to calculate the current bounding box of the children, based on the parent's transformations. I can calculate the scaling and the rotation of the child, but I don't know where it should be positioned relative to the parent because the parent's bounding box is very different from what it was in the beginning. Add weird anchor points to the story and it becomes even more complicated. The perfect solution would be to get the vertices of the original sprite and not the bounding box. Is it possible?
Any ideas? Am I missing something?

The source code of boundingBox() maybe helpful. You can get the affinetransform by nodeToParentTransform(),and use CCPointApplyAffineTransform to get the new position of the four points. Then you can write a new method to check if the touch locate in the new rect.

Assume you Have a parent
CCSprite* parent;
and a Child,
CCSprite* child; //child Tag is 100
you can give it a try in your touch method:
YOUR_CLASS::ccTouchBegan(CCTouch* pTouch, CCEvent* pEvent){
CCPoint touchLocation = parent->convertTouchToNodeSpace(pTouch);
if (CCRect::CCRectContainsPoint(parent->getChildByTag(100)->boundingBox(),touchLocation)){
//do something
CCLOG("touch on child");
}
}

If someone wants to find out the letters bounding boxes in a rotated label:
int maxIdx = label->getStringLength() -1;
Mat4 trans = label->getNodeToParentTransform();
for(int idx = 0; idx<=maxIdx; idx++) {
Sprite* letter = label->getLetter(idx);
Rect letterRect = letter->getBoundingBox();
Point p = PointApplyTransform(letterRect.origin, trans);
Rect rect = Rect(p.x, p.y, 10, 10); // Letter Approximation rect
}

Related

Collision detection & resolution: circle in a playfield of other circles and polygons

I am working on a game that has a player sprite surrounded by a collision circle of a known radius. The player sprite can move about a playfield that consists of other sprites with their own collision circles and other obstacles made up of polygons. The other obstacles are rectangles at a 45 degree angle.
In addition, I want the player to adjust its movement when it does collide. I want the player to try to "push through" past the object instead of being stopped by it.
For example, if the player were to collide with another sprite's bounding circle, it would be stopped if its vector was exactly perpendicular to the tangent of the two circles' intersection.
However, if not perfectly perpendicular, the player would be, slowly at first, then faster, pushed along the tangent of the circle until it can continue past it unimpeded.
This works similarly when encountering one of the 45 degree rectangles.
What I need help with is the following: I am trying to find an analytic solution to detect both other sprites and obsticles, have the player's movement adjusted, and possibly stopped when adjusted to wedge between two or more objects.
I can do the collision detection and deflection for one object type at a time, but am struggling to put everything together into a comprehensive algorithm. I am currently working on an iterative pairwise resolution approach that "tries" different locations to result in a best-guess solution, but I really want a mathematically analytic solution. I'm hoping to have a function something like what appears in this psuedocode.
x = [player's x location]
y = [player's y location]
r = [player's collision radius]
// Array of other sprites on the playfield,
spr = [other sprites array]
// which contains 3 parameters, x, y, r. E.g., spr[3].x or spr[3].r,
// for the x position or collision radius for the fourth sprite in the
// array.
// Array of 45 degree rectangles on the playfield,
rect = [array of rectangles]
// which contain 4 parameters, x1, y1, x2, y2, the two opposite points
// of the rectangle. E.g., rect[0].x1, for the x position of the first
// point of the first rectangle.
// For simplicity, assume the above variables are all directly accessable
// in the function below.
// requestX and requestY is the position to which the player would
// like to move the player sprite.
definefunction collisionAdjustor(requestX, requestY) {
// Here I'd like to adjust the requested position if needed because
// of an intersection with one or more other sprites or rectangles.
// Finally return the location at which the player will actually be
// arriving.
return destinationX, destinationY
}
Any advice or suggestions would be much appreciated.
--Richard

Is corse parent == parent index?

In the H3 library, you can find the corse parent index of a H3 hexagon using the h3ToParent method. Is the corse parent the same as the parent? If not how do I find the true parent index?
The H3 docs generally use "coarse" to indicate larger-hex resolutions with lower numbers (e.g. res 1 hexes, 607,220km2), and "fine" to indicate smaller-hex resolutions with higher numbers (e.g. res 10 hexes, 0.015km2). This is to avoid confusion with "bigger"/"smaller" terminology (is a bigger resolution a large hex or a larger res number?).
The h3ToParent method can return the direct parent of a hexagon (i.e. the coarser hexagon that contains it at the next resolution up), or its ancestor at any given coarser resolution - the second argument specifies the resolution of the parent you want to obtain.
In this image, for example, all of the larger hexagons are "parents" of the smallest hexagon in the center. If the resolution of the center hex is 7, then:
H3Index directParent = h3ToParent(centerHex, 6);
H3Index grandParent = h3ToParent(centerHex, 5);
// etc

Finding the bounds of an area covered by n of m rectangles

I have a set of m non-rotated, integer (pixel) aligned rectangles, each of which may or may not overlap. The rectangles cover thousands of pixels. I need to find the minimum sized bounding box that covers all areas that are covered by n of the m rectangles.
A (dirty) way of doing this is to paint a canvas that covers the area of all the targets. This is O(mk) where m is the number of rectangles and k is the number of pixels per rectangle. However since k is much greater than m I think there is a better solution out there.
This feels like a dynamic programming problem...but I am having trouble figuring out the recursion.
Solution which is better but still not great:
Sort the start and end points of all the rectangles in the X direction O(mlogm), iterate and find the x positions that may have over n rectangles, O(m) loop. For each x position that may have over n rectangles, take the rectangles at that position and sort the starts and stops at that position (O(mlogm)). Find the region of overlap, keep track of the bounds that way. Overall, O(m^2logm).
Hello MadScienceDreams,
Just to clarify, the bounding box is also non-rotated, correct?
If this is the case, then just keep track of the four variables: minX, maxX, minY, maxY–representing left-most, right-most, top-most, and bottom-most pixels–that define the bounding box, loop through each of the rectangles updating the four variables, and defining the new bounding box given those four variables.
EDIT
It looks like you are asking about finding the bounds of some subset of rectangles, not the whole set.
So you have M rectangles, and you choose N rectangles from them, and find the bounds within that.
Even in this situation, looping through the N rectangles and keeping track of their bound would be at most O(m), which isn't bad at all.
I feel that I must be misunderstanding your question since this response isn't what you are probably looking for; is your question actually trying to ask how to precompute the bounds so that given any subset, know the total bounds in constant time?
Is this defines your question? For bounding box => #rect_label >= n
How about we starts with one box and find the next box that has nearest furthest corner from it. Now we have a region with two box. Recursively find the next region, until we have n boxes.
While we need to start on every box, we only need to actively work on the currently smallest regions. The effect is we start from the smallest cluster of boxes and expand out from there.
If n is closer to m than 0, we can reverse the search tree so that we start from the omni-all-enclosing box, chopping off each bordering box to create the next search level. Assuming we only actively work on the smallest remaining region, effect is we chop off the emptiest region first.
Is it too complicated? Sorry I can't remember the name of this search. I'm not good at maths, so I'll skip the O notation. >_<
I propose the following algorithm :
prepareData();
if (findBorder('left')) {
foreach (direction in ['top', 'right', 'bottom']) {
findBorder(direction)
}
} else noIntersectionExists
prepareData (O(mlogm)):
Order vertical bounds and horizontal bounds
Save the result as:
- two arrays that point to the rectangle (arrX and arrY)
- save the index as a property of the rectangle (rectangle.leftIndex, rectangle.topIndex, etc.
findBorder(left): // the other direction are similar
best case O(n), worst case O(2m-n)
arrIntersections = new Array;
//an intersection has a depth (number of rectangles intersected), a top and bottom border and list of rectangles
for(i=0; i < 2*m-n-1; i++){ // or (i = 2*m-1; i > n; i--)
if(isLeftBorder(arrX[i])){
addToIntersections(arrX[i].rectangle, direction);
if(max(intersections.depth) = n) break;
} else {
removeFromIntersections(arrX[i].rectangle, direction);
}
}
addToIntersections(rectangle, direction): // explanations for direction=left
Best case: O(n), worst case: O(m)
hasIntersected = false;
foreach(intersection in intersection){
if(intersect(intersection, rectangle)){
hasIntersected = true
intersections[] = {
depth: intersection.depth,
bottom: min(intersection.bottom, rectangle.bottom),
top: max(...)}
intersection.depth++
intersection.bottom = max(intersection.bottom, rectangle.bottom)
intersection.top = max(...)
}
}
if(!hasIntersected)
intersections[]={depth:1, bottom:rectangle.bottom, top:rectangle.top}
This gives an overall order between O(n^2) and O(m*(m-n/2))
I hope my pseudo code is clear enough

Check mouse in one Model or not?

In XNA 4.0 3D. I want to Drag and Drop one model 3D.So,I must check mouse in a Model or not. My problem is I don't know change position and rate this Model from 3D to 2D. It's related Matrix View and Matrix Projection of camera??
This is my code:
http://www.mediafire.com/?3835txmw3amj7pe
Check out this article on msdn: Selecting an Object with a Mouse.
From that article:
MouseState mouseState = Mouse.GetState();
int mouseX = mouseState.X;
int mouseY = mouseState.Y;
Vector3 nearsource = new Vector3((float)mouseX, (float)mouseY, 0f);
Vector3 farsource = new Vector3((float)mouseX, (float)mouseY, 1f);
Matrix world = Matrix.CreateTranslation(0, 0, 0);
Vector3 nearPoint = GraphicsDevice.Viewport.Unproject(nearsource,
proj, view, world);
Vector3 farPoint = GraphicsDevice.Viewport.Unproject(farsource,
proj, view, world);
// Create a ray from the near clip plane to the far clip plane.
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
Ray pickRay = new Ray(nearPoint, direction);
For proj and view use your own projection and view matrices accordingly.
Now when you have your Ray, you need to have a BoundingBox or a BoundingSphere (or multiple) that are roughly encompassing your model.
A simple solution is to use BoundingSphere properties of ModelMesh for each mesh in your Model.Meshes.
foreach(ModelMesh mesh in model.Meshes)
{
if(Ray.Intersects(mesh.BoundingSphere))
{
//the mouse is over the model!
break;
}
}
Since BoundingSphere of each ModelMesh is going to encompass all vertices in that mesh, it might not be the most precise representation of the mesh if it is not roughly round (i.e. if it is very long). This means that the above code could be saying that the mouse intersects the object, when visually it is way off.
The alternative is to create your bounding volumes manually. You make instances of BoundingBox or BoundingSphere objects as suits your need, and manually change their dimensions and positions based on runtime requirements. This requires slightly more work, but it isn't hard.

how to check if a solid rectangular box is a subset of solid ball

Suppose we have been given the coordinates of the centre of a solid rectangular box, the box's length, breadth, height and a solid ball with a given centre and radius.
Is there a fast way to check if the box is a subset of the ball? The only simple method that comes to my mind is to check if each of the 8 corner vertices lies inside the sphere. If yes, the box is indeed a subset of the ball (by convexity property of the ball).
If you expect that most of the time the box will not be inside the sphere, you can do some quick tests:
if (sphere.center.x+sphere.radius<box.center.x-box.size.x) return false;
if (sphere.center.x-sphere.radius>box.center.x+box.size.x) return false;
etc.
If you expect that the box will usually be far inside the sphere, you can do other quick tests:
bsx = box.size.x;
bsy = box.size.y;
bsz = box.size.z;
box_radius = sqrt(bsx*bsx+bsy*bsy+bsz*bsz)/2;
brx = box.center.x-sphere.center.x;
bry = box.center.y-sphere.center.y;
brz = box.center.z-sphere.center.z;
box_dist = sqrt(brx*brx+bry*bry+brz*brz);
if (box_radius+box_dist<sphere.radius) return true;
You will still need more precise tests if the quick tests fail though.
There are only 4 corners to check, but in fact you only need to check 2 which are diagonal to each other. This follows from the property of the rectangle having straight sides, while the circle is convex, as you state.
Alternatively, consider that if the left upper corner and right lower corner are both within the circle, then the rectangle they form is a boudning box. The circle is obviously not, and thus the rectangle must be a sub-region of the circle.
EDIT: You might be talking about a box and a sphere, in which case the same idea applies, you just have to choose points which have different x, y, and z values

Resources