Why Do Objects Overlap with CGRectIntersectsRect? - ios

I am creating a puzzle game for which you have to move an object around obstacles in order to reach your target. However, for some reason objects are overlapping when I use CGRectIntersectsRect. I want the objects to STOP when they touch edges with each other, NOT when they're overlapping each other. Current code is as follows:
-(void)objectObstacleCollision {
if (CGRectIntersectsRect(object.frame, obstacle1.frame)) {
xMotion = 0;
yMotion = 0;
if (objectMovingUp == YES) {
objectCrashedUp = YES;
objectMovingUp = NO;
if (objectCrashedUp == YES && objectMovingUp == NO) {
up.hidden = YES;
down.hidden = NO;
right.hidden = NO;
left.hidden = NO;
}
}
This is causing objects to overlap upon impact which causes problems when trying to move the object in a different direction. After many different attempts, for the life of me, I cannot get the object to stop when it touches edges with obstacles. How can I get this to happen?

If two rects share an edge, they don't intersect, they touch. For example, this code:
CGRect rect1 = CGRectMake(0, 0, 100, 100);
CGRect rect2 = CGRectMake(0, 100, 100, 100);
if (CGRectIntersectsRect(rect1, rect2)) {
NSLog(#"The intersection rect is %#", NSStringFromCGRect(CGRectIntersection(rect1, rect2)));
} else {
NSLog(#"The rects don't intersect.");
}
will output "The rects don't intersect."
There's no built-in CGRect function to determine if two rects are touching, but you could write one that iterates through the 4 possibilities.

Related

Collision detection between objects in Tiled and a Sprite's bounding box in cocos2d

I am trying to make a platform game for the iphone, using cocos2d and Tiled (for the maps).
All of the tutorials i've seen on the net are using Layers in Tiled to do collision detection.
I want to use objects to do that...not Layers.
With objects you can create custom shapes that can give a better 'reality' into the game.
To give an example of what i mean :
I've drawn the ground as a background and created an object layer on top.
I want to detect player collision with that, instead of the background tile.
Now using the most famous tutorial out there : http://www.raywenderlich.com/15230/how-to-make-a-platform-game-like-super-mario-brothers-part-1
I am trying to rewrite checkForAndResolveCollisions method to check collisions for the objects instead.
The problem is that in Tiled the coordinates system is different than cocos2d. Tiled starts from top left corner, cocos2d from bottom left corner....and not only that...I noticed that the width and height of the object properties in Tiled (probably) dont correspond to the same in iphone devices.
The above rectangle has properties:
its w/h is 480/128 in tiled (for retina devices) which means its probably huge inside the map if i keep them like this. My guess is i have to divide this by 2.
So far i got this:
-(void)checkForAndResolveObjCollisions:(Player *)p {
CCTiledMapObjectGroup *objectGroup = [map objectGroupNamed:#"Collision"];
NSArray* tiles = [objectGroup objects];
CGFloat x, y, wobj, hobj;
for (NSDictionary *dic in tiles) {
CGRect pRect = [p collisionBoundingBox]; //3
x = [[dic valueForKey:#"x"] floatValue];
y = [[dic valueForKey:#"y"] floatValue];
wobj = [[dic valueForKey:#"width"] floatValue];
hobj = [[dic valueForKey:#"height"] floatValue];
CGPoint position = CGPointMake(x, y);
CGPoint objPos = [self tileForPosition:position];
CGRect tileRect = CGRectMake(objPos.x, objPos.y, wobj/2, hobj/2);
if (CGRectIntersectsRect(pRect, tileRect)) {
CCLOG(#"INTERSECT");
CGRect intersection = CGRectIntersection(pRect, tileRect);
NSUInteger tileIndx = [tiles indexOfAccessibilityElement:dic];
if (tileIndx == 0) {
//tile is directly below player
p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y + intersection.size.height);
p.velocity = ccp(p.velocity.x, 0.0);
p.onGround = YES;
} else if (tileIndx == 1) {
//tile is directly above player
p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y - intersection.size.height);
p.velocity = ccp(p.velocity.x, 0.0);
} else if (tileIndx == 2) {
//tile is left of player
p.desiredPosition = ccp(p.desiredPosition.x + intersection.size.width, p.desiredPosition.y);
} else if (tileIndx == 3) {
//tile is right of player
p.desiredPosition = ccp(p.desiredPosition.x - intersection.size.width, p.desiredPosition.y);
} else {
if (intersection.size.width > intersection.size.height) {
//tile is diagonal, but resolving collision vertially
p.velocity = ccp(p.velocity.x, 0.0);
float resolutionHeight;
if (tileIndx > 5) {
resolutionHeight = -intersection.size.height;
p.onGround = YES;
} else {
resolutionHeight = intersection.size.height;
}
p.desiredPosition = ccp(p.desiredPosition.x, p.desiredPosition.y + resolutionHeight );
} else {
float resolutionWidth;
if (tileIndx == 6 || tileIndx == 4) {
resolutionWidth = intersection.size.width;
} else {
resolutionWidth = -intersection.size.width;
}
p.desiredPosition = ccp(p.desiredPosition.x + resolutionWidth , p.desiredPosition.y);
}
}
}
// }
}
p.position = p.desiredPosition; //8
}
- (CGPoint)tileForPosition:(CGPoint)p
{
NSInteger x = (NSInteger)(p.x / map.tileSize.width);
NSInteger y = (NSInteger)(((map.mapSize.height * map.tileSize.width) - p.y) / map.tileSize.width);
return ccp(x, y);
}
I am getting the object x,y,w,h and try to convert them to cocos2d dimensions and sizes.
The above translates to this:
Dimens: 480.000000, 128.000000
Coord: 0.000000, 40.000000
Basically its a mess. And its not working .....at all. The player just falls right through.
I am surprised noone has done collision detection based on objects before...unless i am wrong.
Does anyone know if this can be done or how it can be done ?
Kinda what he does here : https://www.youtube.com/watch?feature=player_detailpage&v=2_KB4tOTH6w#t=30
Sorry for the long post.
Thanks for any answers in advance.

Overlap and Swapping Images in iOS

I want to swap two images. When I move the drag image and it overlaps 50% or greater on any other image in the view it must be swapped. The problem is how can I check the drag image is 50% or more than 50% overlap with the other image. Please help and suggest the logic with a code example.
The code I am trying is :
if (imgVw.tag != self.tag) {
CGRect imgVwRect = CGRectMake(imgVw.frame.origin.x +(imgVw.frame.size.width/2), imgVw.frame.origin.y+(imgVw.frame.size.height/2), imgVw.frame.size.width, imgVw.frame.size.height);
CGRect movingImgRect = CGRectMake(newCenter.x+self.frame.size.width, newCenter.y+self.frame.size.height, self.frame.size.width, self.frame.size.height);
if (movingImgRect.origin.x >= imgVwRect.origin.x && movingImgRect.origin.y >= imgVwRect.origin.y)
{
NSLog(#"img view tag %lu",imgVw.tag);
UIImage *tempImg = self.image;
[self setImage:imgVw.image];
[imgVw setImage:tempImg];
}
}
This is pretty straightforward.
Use the method CGRectIntersection to calculate the intersection of the 2 rects.
Then compare the area of the intersection with the area of the moving rect. Something like this (assuming I understand your code
if (imgVw.tag != self.tag)
{
CGRect imgVwRect = CGRectMake(imgVw.frame.origin.x +(imgVw.frame.size.width/2),
imgVw.frame.origin.y+(imgVw.frame.size.height/2),
imgVw.frame.size.width,
imgVw.frame.size.height);
CGRect movingImgRect = CGRectMake(newCenter.x+self.frame.size.width,
newCenter.y+self.frame.size.height,
self.frame.size.width,
self.frame.size.height);
//Figure out the intersection rect of the 2 rectangles
CGRect intersectionRect = CGRectIntersection(imgVwRect, movingImgRect);
//Find the area of the intersection
CGFloat xArea = intersectionRect.size.height * intersectionRect.size.width;
//Find the area of the moving image
//(this code could be done once and saved in an iVar)
CGFloat movingImgArea = movingImgRect.size.height * movingImgRect.size.width;
//Is the intersection >= 1/2 the size of the moving image?
if (xArea*2 >= movingImgArea)
{
//Do whatever you need to do when the 2 images overlap by >= 50%
}
}

creating walls for simple maze game

i am doing a single view game demo, a maze like game with walls. player will control the character with a UIButton.
basically i have devised that i will need to check that if in the next step, the character is going to intersect with a wall, the character movement will return false. but, i cannot seem to put them together.
i currently have this boolean function to check if the character is going to intersect with the wall
-(Boolean) checkCollision : (CGRect) newFrame{
CGRect frame = self.mainchar.frame;
frame.origin.x = self.currentPoint.x;
frame.origin.y = self.currentPoint.y;
for (UIImageView *image in self.hardwalls) {
if (CGRectIntersectsRect(frame, image.frame)) {
return true;
}
}
return false;
}
my UIButton for movement is
-(IBAction)CharMovingLeft:(id)sender; {
CGPointMake(mainchar.center.x -charmovement, mainchar.center.y);
what should i be adding into the button method so that it will stop this movement when the intersection is going to happen?
thanks in advance
-(IBAction)CharMovingLeft:(id)sender {
CGRect newFrame = YOUR_CHARACTERS_FRAME_IF_IT_MOVED;
if (![self checkCollision:newFrame];
//MOVE CHARACTER:
}
else
//DONT MOVE CHARACTER
}
Will this do ... ?

How to specify position of an UIImage initWithImage to detect collision of the images

I have looked up all related questions to this question but nothing brought success.
The problem is probably pretty simple:
I want to detect a collision between two geometrical objects which are animated in a way they are hitting eachother at a given time.
In order to use the method CGRectIntersectsRect i have to init the UIImage excactly with the size of the actual image of the geometrical object so it returns only a collision if the images/frames really collide.
So how do i specify the postion to place my image i have intiliazid with initWithImage.
I can't use the Method initWithFrame:CGRectMake as i do not want a UIImageview shaped as a rectangle.
Examples which do not work:
circleYellow = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height / 2, 50, 50)];
circleYellow.image = [UIImage imageNamed:images[arc4random() % 5]];
circleYellow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:images[arc4random() % 5]]];
I would recommend you check out cocos2d. It has tools for handling sprites, updating their position through Actions (animations) on the screen, etc.
Detecting the collision of two sprites becomes something like:
-(void)update(float dt)
{
CGRect rect1 = [sprite1 boundingBox];
CGRect rect2 = [sprite2 boundingBox];
if (CGRectIntersectsRect(rect1, rect2))
{
// Do something about the collision...
}
}
And if you need more sophisticated modeling of the motion, or if you want to be able to collide arbitrary shapes and not just the bounding boxes, Box2D built in. There are lots of examples available for this as well.
Was this helpful?
UIImageView and it's superclass UIView always create rectangles. From the UIView class reference:
The UIView class defines a rectangular area on the screen ...
It sounds like SpriteKit may be what you need - check out the sprite kit programming guide.
I would recommend using the SpriteKit:
//Create a SpriteNode loading your image
SKSpriteNode *cicleYellow = [SKSpriteNode spriteNodeWithImageNamed:images[arc4random() % 5]];
//Set the size and the position of the Sprite
circleYellow.size = CGSizeMake(50,50);
circleYellow.position = CGPointMake(0, self.view.frame.size.height);
//Create a circlePhisicsBody and add it to the Sprite
SKPhysicsBody *circlePhisicsBody = [SKPhysicsBody bodyWithCircleOfRadius:cicleYellow.size.width/2.0f];
cicleYellow.physicsBody = circlePhisicsBody;
Check out the Apple documentation on how to use the Sprite Kit.
You would need some timer function to check that every now and then but the algorihm for detecting collisions among Rectangles is pretty straight forward (square A and square B):
//If any of the sides from A are outside of B
if( bottomA <= topB ) { return false; }
if( topA >= bottomB ) { return false; }
if( rightA <= leftB ) { return false; }
if( leftA >= rightB ) { return false; }
//If none of the sides from A are outside B return true;
If you need to do it for circles only here is a good tutorial: http://gamedevelopment.tutsplus.com/tutorials/when-worlds-collide-simulating-circle-circle-collisions--gamedev-769

Keeping SKSpriteNode in bounds of screen

I am trying to check whether my SKSpriteNode will remain in bounds of the screen during a drag gesture. I've gotten to the point where I am pretty sure my logic toward approaching the problem is right, but my implementation is wrong. Basically, before the player moves from the translation, the program checks to see whether its in bounds. Here is my code:
-(CGPoint)checkBounds:(CGPoint)newLocation{
CGSize screenSize = self.size;
CGPoint returnValue = newLocation;
if (newLocation.x <= self.player.position.x){
returnValue.x = MIN(returnValue.x,0);
} else {
returnValue.x = MAX(returnValue.x, screenSize.width);
}
if (newLocation.y <= self.player.position.x){
returnValue.y = MIN(-returnValue.y, 0);
} else {
returnValue.y = MAX(returnValue.y, screenSize.height);
}
NSLog(#"%#", NSStringFromCGPoint(returnValue));
return returnValue;
}
-(void)dragPlayer: (UIPanGestureRecognizer *)gesture {
CGPoint translation = [gesture translationInView:self.view];
CGPoint newLocation = CGPointMake(self.player.position.x + translation.x, self.player.position.y - translation.y);
self.player.position = [self checkBounds:newLocation];
}
For some reason, my player is going off screen. I think my use of the MIN & MAX macros may be wrong, but I am not sure.
Exactly, you mixed up MIN/MAX. The line MIN(x, 0) will return the lower value of x or 0, meaning the result will be 0 or less.
At one line you're using -returnValue.y which makes no sense.
You can (and should for readability) omit the if/else because MIN/MAX, if used correctly, make if/else unnecessary here.

Resources