CGRectIntersection requires scalar type? - objective-c

I am trying to check collisions of objects from a NSMutableArray against another object (using a CGRect) but it keeps saying the method requires a scalar type?!
Here is the method throwing the error:
-(void) checkSquareToCircleCollisions{
NSMutableArray *array = [squares getSquares];
for(int i = 0; i < [squares getCount]; i++){
Square *s = [array objectAtIndex: i];
CGRect rect1 = [player getRect];
CGRect rect2 = [s getRect];
//if(CGRectIntersection(rect1, rect2)){
//[player setAlive: NO];
// }
}
}

Use CGRectIntersectsRect, not CGRectIntersection.
CGRectIntersectsRect returns a boolean: YES if the rectangles intersect. CGRectIntersection returns the CGRect that is the overlap (if any) between the two rectangles.
if (CGRectIntersectsRect(playerRect, squareRect)) {
player.alive = NO;
}

Related

SpriteKit enumerateChildNodesWithName with advanced searching?

The following code doesn't work as expected. According to the SPRITE KIT PROGRAMMING GUIDE, pages 61 and 62 one may perform "advanced searches" by using regular expression like syntax, so, unless I'm misunderstanding the implementation, this should work?
SKShapeNode *myCircle = [self getCircle];
myCircle.name = [NSString stringWithFormat:#"CIRCLE_%d_%d", x, y];
myCircle.position = CGPointMake(10,10);
[self addChild:myCircle];
// Lets remove ALL SKNodes that begin with the name "CIRCLE_"
[self enumerateChildNodesWithName:#"CIRCLE_*" usingBlock:^(SKNode *node, BOOL *stop) {
[node removeFromParent];
}];
But alas, the nodes do not go away. If I specify an exact name (like #"CIRCLE_10_10") it works, but the wildcard expression * doesn't seem to, nor does something like this #"CIRCLE_[0-9]+_[0-9]+" -- not even if I use slashes #"/CIRCLE_[0-9]+_[0-9]+".
What am I doing wrong?
EDIT:
THIS WORKS and I could implement regular expression matching instead of substring'ing, but hoping to get the Sprite Kit implementation working (ideally).
[[self children] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
SKNode *node = (SKNode *)obj;
if ([[node.name substringWithRange:NSMakeRange(0, 7)] isEqual: #"CIRCLE_"]) {
[node removeFromParent];
}
}];
I tried the following variation of your code in both the current and beta versions of Xcode on both iOS and OS-X.
SKScene *scene = [[SKScene alloc] initWithSize:self.gameView.frame.size];
for (int x = 0; x < 20; x++)
{
for (int y = 0; y < 20; y++)
{
CGPathRef myPath = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 20, 20), NULL);
SKShapeNode *myCircle = [[SKShapeNode alloc] init];
myCircle.path = myPath;
#if TARGET_OS_IPHONE
myCircle.fillColor = [UIColor redColor];
#else
myCircle.fillColor = [NSColor redColor];
#endif
myCircle.name = [NSString stringWithFormat:#"CIRCLE_%d_%d", x, y];
myCircle.position = CGPointMake(20*x,20*y);
[scene addChild:myCircle];
CGPathRelease(myPath);
}
}
[self.gameView presentScene:scene];
All of your sample expressions work on the Mac in both versions of the SDK. On iOS, however, they only worked in the Developer Preview.

Objective-C - Position Object with CGPoint from another Method

Hello i have got a question. I hope anybody could help me. I do not understand… I have a method returnPointFromArray where i have an array with values (e.g. 50.0, 100.0). Than i want to random it and then i want to use the CGPoint p in the Method drawObjectWithPoint to position my Object (object from another class) with the random value.
But the drawObjectWithPoint Method says always that the CGPoint p ist 0.0, 0,0 or he says "Use of undeclared identifier p or "instance variable hides…" .
I tried the same principle to test with int and this works.
I don´t know what i´m doing wrong.
It would be great if anybody could help me and explain what i´m doing wrong.
Thanks a lot.
.h
-(void)returnPointFromArray;
-(void)drawObjectWithPoint;
.m
-(void)returnPointFromArray
{
NSArray *points = [];
//Random for points
NSUInteger *randomIndex = arc4random() % [points count];
NSValue *val = [points objectAtIndex:randomIndex];
CGPoint p = [val CGPointValue];
}
-(void)drawObjectWithPoint
{
Object *myObject [[Object alloc]init];
CGPoint pNew = p;
myObject.position =
[self addChild:myObject];
}
You can do this: Edited: (This is how yo declare in .h file)
in .h file
#import <UIKit/UIKit.h>
#interface MyClass : UIViewController {
CGPoint p;
}
-(void)returnPointFromArray;
-(void)drawObjectWithPoint;
#end
in .m file
-(void)returnPointFromArray {
NSArray *points = [];
//Random for points
NSUInteger *randomIndex = arc4random() % [points count];
NSValue *val = [points objectAtIndex:randomIndex];
p = [val CGPointValue]; // change here
}
-(void)drawObjectWithPoint {
Object *myObject [[Object alloc]init];
CGPoint pNew = p;
myObject.position =
[self addChild:myObject];
}
assign value directly by method call
-(void)drawObjectWithPoint
{
Object *myObject [[Object alloc]init];
myObject.position = [self returnPointFromArray];
[self addChild:myObject];
}
-(CGPoint)returnPointFromArray {
NSArray *points = [];
//Random for points
NSUInteger *randomIndex = arc4random() % [points count];
NSValue *val = [points objectAtIndex:randomIndex];
return [val CGPointValue];
}
Just declared CGPoint p; in .h file. You declared it as locally(returnPointFromArray function) means its scope is local for that function only. check here
for reference.
Your returnPointFromArray method returns void - just modify it -
-(CGPoint)returnPointFromArray
{
// your code
return p;
}
Then where you want to use p, just write
CGPoint pNew = [self returnPointFromArray];
obviously you'll have to add code which actually uses this value - your code doesn't do this at all -
myObject.position = pNew;

Reversing sprite animation

After making adjustments to my code as suggested, my animation now works. Now, I'd like to ask how to reverse the movements of the sprite. I am trying to make the sprite move as if the wind is blowing in it. Here's my code now:
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super's" return value
if( (self=[super init]) ) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
self.isTouchEnabled = YES;
CCSprite *black = [CCSprite spriteWithFile:#"b.png"];
black.position = ccp(100, 160);
black.scaleX = 100 / black.contentSize.width;
black.anchorPoint = ccp(0.03, 0);
CCSpriteFrameCache *frame = [CCSpriteFrameCache sharedSpriteFrameCache];
[frame addSpriteFramesWithFile:#"bLongAnimation.plist"];
CCSpriteBatchNode *bHair = [CCSpriteBatchNode batchNodeWithFile:#"bLongAnimation.png"];
[self addChild:bHair];
[self addChild:black z:1 tag:1];
//Animation
NSMutableArray *animateBlackHair = [NSMutableArray arrayWithCapacity:10];
for (int i = 1; i < 10; i++)
{
NSString *animBlackHair = [NSString stringWithFormat:#"b%i.png", i];
CCSpriteFrame *blackFrame = [frame spriteFrameByName:animBlackHair];
[animateBlackHair addObject:blackFrame];
//I added this code block thinking it might work
for(i = 10; i > 1; i--)
{
NSString *revAnimation = [NSString stringWithFormat:#"bRightLong%i.png", i];
CCSpriteFrame *revFrame = [frame spriteFrameByName:revAnimation];
[animateBlackHair1 addObject:revFrame];
}
}
CCAnimation *blowHair = [CCAnimation animationWithSpriteFrames:animateBlackHair delay:0.1];
CCAction *blowingHair = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:blowHair]];
[black runAction:blowingHair];
}
return self;}
My guess didn't work so I was wondering how I can reverse the movements as soon as it finishes the first one?
UPDATE: Never mind, I figured it out. I just moved the for loop for reversing the action outside of the other loop. Thank you for the help.
Try setting the delay on the animation to something other than 0. Try 0.1 or 0.4 or something. If you set it to zero I don't think the animation runs, and if it does, it runs too fast to be visible.

Annotations in MapView

I have this code:
-(void)handleLongPressGesture:(UIGestureRecognizer*)sender {
NSNumber* existingpoints = [[NSNumber alloc]init];
existingpoints =[NSNumber numberWithInt:0];
// This is important if you only want to receive one tap and hold event
if (sender.state == UIGestureRecognizerStateEnded)
{
[self.mapView removeGestureRecognizer:sender];
}
else {
do {
int z = 1;
existingpoints =[NSNumber numberWithInt:z];
// Here we get the CGPoint for the touch and convert it to latitude and longitude coordinates to display on the map
CGPoint point = [sender locationInView:self.mapView];
CLLocationCoordinate2D locCoord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
// Then all you have to do is create the annotation and add it to the map
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init]; annotationPoint.coordinate = locCoord;
NSString *latitude = [[NSString alloc] initWithFormat:#"%f",locCoord.latitude];
NSString *longitude = [[NSString alloc] initWithFormat:#"%f", locCoord.longitude];
annotationPoint.title = #"Event";
annotationPoint.subtitle = [NSString stringWithFormat:#"%# & %#", latitude, longitude];
[mapView addAnnotation:annotationPoint];
[[NSUserDefaults standardUserDefaults]setObject:latitude forKey:#"FolderLatitude"];
[[NSUserDefaults standardUserDefaults]setObject:longitude forKey:#"FolderLongitude"];
} while ([existingpoints intValue] == 0);
}
}
...but the problem is that when I hold, and then drag more than one pin is added. I want to add only one pin. So I tried the do method but it doesn't work. I can't understand, because when I executed the code I turn the value of the NSNumber to 1, and the while says = 0 to run the code.
Please Help!!
Your current code is prone to have quite a number of memory leaks. For example:
NSNumber* existingpoints = [[NSNumber alloc] init];
existingpoints = [NSNumber numberWithInt:0];
Is leaking because you leave the first instance of existingpoints with retain value of 1 and not freeing it anywhere. Unless you're using ARC. You can optimize the above code with just one instruction:
NSNumber* existingpoints = [NSNumber numberWithInt:0];
And retain it if you need to keep it somewhere (but i belive it's not the case).
Analyzing the code, I'd recommend NOT to use existingpoints as an NSNumber. Use an NSInteger instead (which is not an object, just a typedef to long).
Here's my rewritten code:
-(void)handleLongPressGesture:(UIGestureRecognizer*)sender {
NSInteger existingpoints = 0;
// This is important if you only want to receive one tap and hold event
if (sender.state == UIGestureRecognizerStateEnded) {
[self.mapView removeGestureRecognizer:sender];
}
else {
do {
int z = 1;
existingpoints = z;
// Here we get the CGPoint for the touch and convert it to latitude and longitude coordinates to display on the map
CGPoint point = [sender locationInView:self.mapView];
CLLocationCoordinate2D locCoord = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
// Then all you have to do is create the annotation and add it to the map
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = locCoord;
NSString *latitude = [NSString stringWithFormat:#"%f",locCoord.latitude];
NSString *longitude = [NSString stringWithFormat:#"%f", locCoord.longitude];
annotationPoint.title = #"Event";
annotationPoint.subtitle = [NSString stringWithFormat:#"%# & %#", latitude, longitude];
[mapView addAnnotation:annotationPoint];
[[NSUserDefaults standardUserDefaults] setObject:latitude forKey:#"FolderLatitude"];
[[NSUserDefaults standardUserDefaults] setObject:longitude forKey:#"FolderLongitude"];
[annotationPoint release]; // Remove this if you're using ARC.
} while (existingpoints == 0);
}
}
Note that I've also changed the code for creating latitude and longitude for not to create any memory leaks when using ARC.
EDIT:
Further analyzing your code, I don't see why this method would be dropping two pins at once. Maybe you could check if your method is not being called twice?
More: Why do you have a do/while loop if you just want it to run once? (but maybe you're just paving your ground to further ahead)

Accessing data from an NSDictionary

I'm using the following method to access data about an object. The first NSLog shows all of the data. The second NSLog shows the 'frame' data which comes out as: NSRect: {{168, 102}, {5, 5}}
How can I access the first set of coordinates from the NSRect and then the abscissa from the first pair?
-(void) moveTheShape:(NSTimer*)timer
{
NSDictionary *userInfo = [timer userInfo];
NSLog(#"Info: %#",userInfo);
//Info: <Shape: 0x68b6c30; frame = (151 352; 5 5); layer = <CALayer: 0x68b6c00>>
NSDictionary *frame = [userInfo valueForKey:#"frame"];
NSLog(#"frame: %#", frame);
//NSRect: {{168, 102}, {5, 5}}
}
CORRECT SOLUTION:
-(void) moveTheShape:(NSTimer*)timer
{
Shape *userInfo = [timer userInfo];
NSLog(#"Info: %#",userInfo);
CGPoint origin = userInfo.frame.origin;
NSLog(#"result: %f", origin.x);
}
The CGRect is stored as NSValue
You will need to get the CGRectValue from the NSValue
Use The following
NSValue *value = [userInfo valueForKey:#"frame"];
CGRect rect = [value CGRectValue];
If my hunch about the type of userInfo is correct:
-(void) moveTheShape:(NSTimer*)timer
{
Shape *userInfo = [timer userInfo];
CGPoint origin = userInfo.frame.origin;
// Do stuff with origin
}
int abscissa = frame.origin.x; will get you the x value. You use frame.size.width and frame.size.height to get the sizes.
Ha, abscissa, my new word for the day!
Anyhow, do you mean CGRect, as an iPhone uses CoreGraphics, not FoundationKit for all UIKit rectangles.
As for the accessing the struct's internal vars (CGPoint and CGSize to be exact), just use regular old dot notation after storing the frame into a CGRect var like so:
NSValue *value = [userInfo objectForKey:#"frame"];
CGRect frameVar = [value CGRectValue];
frameVar.origin = CGPointMake(someCoord, someOtherCoord);