CGRect intersection from child to self - objective-c

Question
How to achieve an intersection of two sprites, when one is a child of self and the other is a child of a sprite?
As their positions are completely different relevant to the comparisons between each other?
Example; this is ran before each frame to determine whether they intersect
-(void)checkInFOVWithPlayer:(Player *)player andEnemy:(Player *)enemy {
SKNode *node = [player childNodeWithName:player.playersFOVName];
if (CGRectIntersectsRect(node.frame, enemy.frame)) {
// [self playerAimAtEnemy:enemy withPlayer:player];
NSLog(#"inframe");
} else {
NSLog(#" ");
}
}
However, node is a child of player and enemy is a child of self. So how can you check if they intersect?
Here's where they're initialised
float radianAngle = ((fovAngle) / 180.0 * M_PI);
float fovOpposite = atanf(radianAngle) * fovDistance;
SKShapeNode *fov = [SKShapeNode node];
UIBezierPath *fovPath = [[UIBezierPath alloc] init];
[fovPath moveToPoint:CGPointMake(0, 0)];
[fovPath addLineToPoint:CGPointMake(fovOpposite *-1, fovDistance)];
[fovPath addLineToPoint:CGPointMake(fovOpposite, fovDistance)];
[fovPath addLineToPoint:CGPointMake(0, 0)];
fov.path = fovPath.CGPath;
fov.lineWidth = 1.0;
fov.strokeColor = [UIColor clearColor];
fov.antialiased = NO;
fov.fillColor = [UIColor greenColor];
fov.alpha = 0.2;
fov.name = #"playerFOV";
[_playerImage addChild:fov];
and enemy
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"enemyImage" ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:bundle];
SKTexture *texture = [SKTexture textureWithImage:image];
_enemy = [Player spriteNodeWithTexture:texture];
_enemy.position = CGPointMake(100, 100);
_enemy.size = CGSizeMake(20, 20);
_enemy.playerAimAngle = [self returnRandomNumberBetween:0 to:360];
_enemy.anchorPoint = CGPointMake(0.5, 0.5);
_enemy.playerHealth = 100;
_enemy.playerIsDead = false;
[self addChild:_enemy];

-(void)checkInFOVWithPlayer:(Player *)player andEnemy:(Player *)enemy {
SKNode *fovNode = [player childNodeWithName:player.playersFOVName];
SKNode *node = [self childNodeWithName:#"enemy"];
CGPoint newPosition = [self convertPoint:node.position toNode:fovNode.parent];
if (CGRectContainsPoint(fovNode.frame, newPosition)) {
[self playerAimAtEnemy:enemy withPlayer:player];
}
}
This has ended up being my solution to the problem, Now however, I must find a way to change the frame of the node so that it is not rectangular.

Related

Image not centered vertically in scrollview

What am I missing? The inner scrollview and the image view fill the entire screen. But somehow my image is not centered. The top left corner of the image starts in the center of the view, but I would like to have the image nicely centered. Also during zooming.
-(void)prepareScrollView
{
for(int i =0;i<[self.layoverPhotoAssets count];i++){
PHAsset *asset = self.layoverPhotoAssets[i];
FMImageZoomViewController *zoomController = [[FMImageZoomViewController alloc] init];
// UIImageView *imageView = [[UIImageView alloc] init];
int x = self.scrollView.frame.size.width * i;
zoomController.view.frame = CGRectMake(x, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
//zoomController.view.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
[self.scrollView addSubview:zoomController.view];
zoomController.zoomScroller.delegate = self;
zoomController.imageView.tag = 1;
[self.zoomControllers addObject:zoomController];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeFast;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:zoomController.zoomScroller.frame.size contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(result){
zoomController.imageView.image = result;
zoomController.imageView.backgroundColor = [UIColor redColor];
}
});
}];
//self.scrollView.contentSize= ;
}
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * [self.layoverPhotoAssets count], 0)];
[self scrollToAsset:self.selectedAsset];
}
Consider:
zoomController.view.frame = CGRectMake(x, 0, self.scrollView.frame.size.width, self.scrollView.frame.size.height);
[self.scrollView addSubview:zoomController.view];
That cannot be right. If zoomController.view is to be a subview of self.scrollView, its frame within self.scrollView is in terms of the bounds of self.scrollView, not the frame of self.scrollView.
Solved it like this:
-(void)prepareScrollView
{
for(int i =0;i<[self.layoverPhotoAssets count];i++){
PHAsset *asset = self.layoverPhotoAssets[i];
FMImageZoomViewController *zoomController = [[FMImageZoomViewController alloc] init];
// UIImageView *imageView = [[UIImageView alloc] init];
int x = self.scrollView.frame.size.width * i;
zoomController.view.frame = CGRectMake(x, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height);
//zoomController.view.frame = CGRectMake(0,0,self.view.bounds.size.width,self.view.bounds.size.height);
[self.scrollView addSubview:zoomController.view];
zoomController.zoomScroller.delegate = self;
[self.zoomControllers addObject:zoomController];
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
options.resizeMode = PHImageRequestOptionsResizeModeExact;
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; //I only want the highest possible quality
options.synchronous = NO;
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestImageForAsset:asset targetSize:zoomController.zoomScroller.bounds.size contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
if(result){
zoomController.imageView = [[UIImageView alloc] initWithImage:result];
zoomController.imageView.frame = zoomController.zoomScroller.bounds;
[zoomController.imageView setContentMode:UIViewContentModeScaleAspectFit];
zoomController.imageView.clipsToBounds = YES;
[zoomController.imageView setCenter: self.scrollView.center];
zoomController.imageView.tag = 1;
[zoomController.zoomScroller addSubview:zoomController.imageView];
// zoomController.imageView.contentMode = UIViewContentModeCenter;
// if (zoomController.imageView.bounds.size.width > result.size.width && zoomController.imageView.bounds.size.height > result.size.height) {
// zoomController.imageView.contentMode = UIViewContentModeScaleAspectFit;
// }
}
});
}];
//self.scrollView.contentSize= ;
}
[self.scrollView setContentSize:CGSizeMake(self.scrollView.frame.size.width * [self.layoverPhotoAssets count], 0)];
[self scrollToAsset:self.selectedAsset];
}

Resize cropped image

Have the similar problem as this post:
How to remove the transparent area of an UIImageView after masking?
but solution doesn't help me, in my case I am cropping image to multi parts, and every part has bounds like parent image had, this is cropping function:
- (UIImage*) maskImage:(CALayer *) sourceLayer toAreaInsidePath:(UIBezierPath*) maskPath;
{
return [self compositeImage:sourceLayer onPath:maskPath usingBlendMode:kCGBlendModeSourceIn];
}
- (UIImage*) compositeImage:(CALayer *) layer onPath:(UIBezierPath*) path usingBlendMode:(CGBlendMode) blend;
{
UIGraphicsBeginImageContext([layer frame].size);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *sourceImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContext([layer frame].size);
[path fill];
[sourceImage drawInRect:[layer frame] blendMode:blend alpha:1.0];
UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return maskedImage;
}
and how I am using it:
- (PuzzlePart *)calculate:(NSDictionary *) item
{
UIBezierPath *path = [self calculatePath:[item objectForKey:#"figure"]];
UIImageView *iView = [[UIImageView alloc] initWithImage:image];
//iView.contentMode = UIViewContentModeCenter;
UIImage *imagePart = [self maskImage:iView.layer toAreaInsidePath:path];
iView.image = imagePart;
return [[PuzzlePart alloc] initWithParams:imagePart lhckID:lifehackID];
}
- (UIBezierPath *)calculatePath:(NSArray *) points {
UIBezierPath *path = [UIBezierPath bezierPath];
NSDictionary *point = [points objectAtIndex:0];
[path moveToPoint:CGPointMake([point[#"x"] intValue], [point[#"y"] intValue])];
for (int i = 1; i < [points count]; i++) {
point = [points objectAtIndex:i];
[path addLineToPoint:CGPointMake([point[#"x"] intValue], [point[#"y"] intValue])];
}
[path closePath];
return path;
}
and place it:
- (void)placeItems
{
for (PuzzlePart *part in puzzleParts) {
UIImage *imagePart = [part imagePart];
CGRect newRect = [self cropRectForImage:imagePart];
UIImage *image = [self imageWithImage:imagePart convertToSize:newRect.size];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
//imageView.contentMode = UIViewContentModeCenter;
imageView.center = CGPointMake([self getRandomNumberBetween:0 to:self.view.frame.size.width],
[self getRandomNumberBetween:0 to:self.view.frame.size.height]);
[self.view addSubview:imageView];
while ([self viewIntersectsWithAnotherView:self.view chosenView:imageView]) {
viewPositionMovingStep++;
[self placeItem:self.view:imageView];
}
}
[self startCountdown];
}
[self cropRectForImage:imagePart] is the same method from post I marked
and this what I have after:
any ideas? Thank you!

altering trajectory using UIKit Dynamics ios7

While trying to replicate the game “Breakout” using ios7’s UIKit Dynamics, I have not been able to figure out how to alter an items trajectory.
In the game, the trajectory of the ball is determined based on where it strikes the paddle. What method/s should I call to alter regular trajectory calculations.
What I have so far is copied below. Thanks for your help.
viewDidLoad.m
- (void)viewDidLoad
{
[super viewDidLoad];
unstruckBlocks = [NSMutableArray array];
[self drawBlocks];
gameHasBegun = NO;
// Set ball image
NSString *ballImagePath = [[NSBundle mainBundle] pathForResource:#"ball" ofType:#"png" inDirectory:#"pongAssets"];
ballView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:ballImagePath]];
[ballView setOpaque:NO];
// Set paddle image
NSString *paddleImagePath = [[NSBundle mainBundle] pathForResource:#"paddle" ofType:#"png" inDirectory:#"pongAssets"];
paddleView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:paddleImagePath]];
[paddleView setOpaque:NO];
dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
paddleDynamicBehavior = [[UIDynamicItemBehavior alloc] initWithItems:#[paddleView]];
ballDynamicBehavior = [[UIDynamicItemBehavior alloc] initWithItems:#[ballView]];
blockDynamicBehavior = [[UIDynamicItemBehavior alloc] initWithItems:unstruckBlocks];
pushBehavior = [[UIPushBehavior alloc] initWithItems:#[ballView] mode:UIPushBehaviorModeInstantaneous];
collisionBehavior = [[UICollisionBehavior alloc] initWithItems:unstruckBlocks];
collisionBehavior.collisionDelegate = self;
[collisionBehavior addItem:paddleView];
[collisionBehavior addItem:ballView];
paddleDynamicBehavior.allowsRotation = NO;
paddleDynamicBehavior.density = 100000000;
paddleDynamicBehavior.elasticity = 1.0;
[dynamicAnimator addBehavior:paddleDynamicBehavior];
ballDynamicBehavior.allowsRotation = NO;
ballDynamicBehavior.elasticity = 1.0;
ballDynamicBehavior.friction = 0.0;
ballDynamicBehavior.resistance = 0.0;
[dynamicAnimator addBehavior:ballDynamicBehavior];
blockDynamicBehavior.allowsRotation = NO;
blockDynamicBehavior.elasticity = 1.0;
blockDynamicBehavior.friction = 0.0;
blockDynamicBehavior.resistance = 0.0;
blockDynamicBehavior.density = 100000000;
[dynamicAnimator addBehavior:blockDynamicBehavior];
pushBehavior.pushDirection = CGVectorMake(0.3, 0.9);
pushBehavior.magnitude = 0.5;
pushBehavior.active = NO;
[dynamicAnimator addBehavior:pushBehavior];
collisionBehavior.collisionMode = UICollisionBehaviorModeEverything;
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[dynamicAnimator addBehavior:collisionBehavior];
}
I think u should modify your code as
pushBehavior.active = Yes;
it might helps you.

Move to few point with CAKeyframeAnimation

I have code :
NSMutableArray * pathArray = [[NSMutableArray alloc]init];
CGPoint currentPoint = CGPointMake(xp, yp);
[pathArray addObject:[NSValue valueWithCGPoint: currentPoint]];
NSMutableArray * pathArray = [algorithm CreatePath];
CGMutablePathRef path = CGPathCreateMutable();
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.values = pathArray;
pathAnimation.path = path;
pathAnimation.duration = 1.0;
[self.firstBall.ballLayer addAnimation:pathAnimation forKey:#"position"];
And in path array I have few CGPoints wrapped in NSValue. But when animation go its only move from first to last coordinate? Why it not use other points?
New code:
-(void)MoveBallWithAlgorithm:(CGPoint)start end:(CGPoint)end;
{
FindWayAlgorithm *algorithm = [[FindWayAlgorithm alloc]init];
algorithm.LX = algorithm.LY = self.columns;
[algorithm CreateBoard:self.fieldsArray];
[algorithm FindWay:start end:end];
CGMutablePathRef path = CGPathCreateMutable();
NSMutableArray * pathArray = [algorithm CreatePath];
#try
{
CGPathMoveToPoint(path, NULL, self.firstBall.ballCoordinates.x, self.firstBall.ballCoordinates.y);
for (NSValue * pointValue in pathArray) {
CGPoint point = [pointValue CGPointValue];
Field* field = [self FindFieldWithPoint:point];
CGPathAddLineToPoint(path, NULL, field.ballCoordinates.x, field.ballCoordinates.y);
}
}
#catch(NSException* ex)
{
NSLog(#"Bug captured when move ball with algorithm: %# %#",ex, [NSThread callStackSymbols]);
}
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.duration = 2.0;
pathAnimation.path = path;
[pathAnimation setDelegate:self];
[self.firstBall.ballLayer addAnimation:pathAnimation forKey:#"position"];
}
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
NSInteger firstBallIndex = [self.fieldsArray indexOfObject:self.firstBall];
NSInteger secondBallIndex = [self.fieldsArray indexOfObject:self.secondBall];
self.ballFrom = [self.fieldsArray objectAtIndex:firstBallIndex];
self.ballTo = [self.fieldsArray objectAtIndex:secondBallIndex];
self.ballTo.ballLayer = self.ballFrom.ballLayer;
CGPoint endPt = CGPointMake(self.secondBall.ballCoordinates.x,self.secondBall.ballCoordinates.y);
self.ballTo.ballLayer.frame = CGRectMake(endPt.x, endPt.y, self.ballSize, self.ballSize);
self.ballFrom.ballLayer = nil;
[self.fieldsArray replaceObjectAtIndex:firstBallIndex withObject:self.ballFrom];
[self.fieldsArray replaceObjectAtIndex:secondBallIndex withObject:self.ballTo];
self.firstBall = nil;
self.secondBall = nil;
}
My problem is resolved. I add:
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
Now my layer not back to first position ;)
The CAKeyframeAnimation documentation states:
Specifying a path overrides the values property.
so you should not set pathAnimation.path if you want to set the keyframe values with
pathAnimation.values = pathArray.
I tested it with a simple label and the following code:
NSArray * pathArray = #[
[NSValue valueWithCGPoint:CGPointMake(10., 10.)],
[NSValue valueWithCGPoint:CGPointMake(100., 10.)],
[NSValue valueWithCGPoint:CGPointMake(10., 100.)],
[NSValue valueWithCGPoint:CGPointMake(10., 10.)],
];
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.values = pathArray;
pathAnimation.duration = 5.0;
[self.label.layer addAnimation:pathAnimation forKey:#"position"];

how to set the frame rate for CABasicAnimation when animation begins in iPhone sdk

I am having multiple Imageview's where I am dividing the 360 degrees/no.of.Imageviews to get an angle to rotate each Imageview.
#define angle ((2*M_PI)/13.0)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
mainView.backgroundColor = [UIColor blackColor];
for(currentIndex = 0; currentIndex < 13; currentIndex++)
{
UIImageView *imageView = [self getCardsWithAngle:(currentIndex*angle)];
[mainView addSubview:imageView];
}
}
-(UIImageView *)getCardsWithAngle:(float)aAngle
{
CGRect frame = CGRectMake(mainView.center.x+50, mainView.center.y-100, 250,200);
CGPoint anchorPoint = CGPointMake(0.5,1.5);
imgView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"card_1.png"]];
imgView.frame = frame;
imgView.backgroundColor = [UIColor clearColor];
if(aAngle == 0.0)
{
imgView.layer.anchorPoint = anchorPoint;
return imgView;
}
imgView.layer.anchorPoint = anchorPoint;
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat:aAngle];
rotationAnimation.duration = 3.0;
rotationAnimation.removedOnCompletion = NO;
rotationAnimation.fillMode = kCAFillModeForwards;
rotationAnimation.delegate = self;
[rotationAnimation setValue:[NSNumber numberWithFloat:aAngle] forKey:#"finalAngle"];
[imgView.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
return imgView;
}
Here My problem is all the imageviews start animating at a time. I want to rotate the image views to an angle one after another.
Any ideas will be appreciated,
Thanks all