altering trajectory using UIKit Dynamics ios7 - 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.

Related

CAGradientLayer in UILabel in UIStackView

This is a custom UIView subclass for a tableHeaderView.
I'm currently trying to put a gradient to an UILabel that's in a vertical UIStackView. It works really well without gradient even in RTL languages (gets moved to the right), but as soon as I add the gradient, the label that's the maskView of the gradientView gets completely out of its place. Here the code for better comprehension:
- (instancetype)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle colors:(NSArray<UIColor *> *)colors {
if (self = [super initWithFrame:CGRectMake(0, 0, self.superview.frame.size.width, 200)]) {
// Labels
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.text = title;
titleLabel.font = [UIFont boldSystemFontOfSize:42.f];
titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[titleLabel sizeToFit];
UILabel *subtitleLabel = [[UILabel alloc] init];
subtitleLabel.text = subtitle;
subtitleLabel.font = [UIFont systemFontOfSize:24.f];
subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[subtitleLabel sizeToFit];
// Create gradient
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = titleLabel.bounds;
NSMutableArray *cgcolors = [NSMutableArray new];
for (int i = 0; i < colors.count; i++) {
cgcolors[i] = (id)colors[i].CGColor;
}
gradient.colors = cgcolors;
gradient.locations = #[#0, #1];
UIView *gradientView = [[UIView alloc] initWithFrame:titleLabel.bounds];
[gradientView.layer addSublayer:gradient];
[gradientView addSubview:titleLabel];
gradientView.maskView = titleLabel;
// Stack
UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:#[gradientView, subtitleLabel]];
stackView.alignment = UIStackViewAlignmentLeading;
stackView.axis = UILayoutConstraintAxisVertical;
stackView.distribution = UIStackViewDistributionEqualCentering;
stackView.spacing = 0;
stackView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:stackView];
[NSLayoutConstraint activateConstraints:#[
[stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:25],
[stackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
[stackView.heightAnchor constraintEqualToConstant:titleLabel.frame.size.height + subtitleLabel.frame.size.height]
]];
}
return self;
}
With LTR languages, it looks good, but with RTL languages, the frame of the gradientView that contains the titleLabel becomes {[width of subtitleLabel], 0, 0, 0} for no reason. The cause is the gradient view, because without it it works fine, but I can't find why.
I tried titleLabel.layer.mask, placing the gradient block at the end, but nothing worked.
EDIT :
Working code:
- (instancetype)initWithTitle:(NSString *)title subtitle:(NSString *)subtitle colors:(NSArray<__kindof UIColor *> *)colors {
if (self = [super initWithFrame:CGRectMake(0, 0, self.superview.frame.size.width, 200)]) {
// Labels
UILabel *titleLabel = [[UILabel alloc] init];
titleLabel.text = title;
titleLabel.font = [UIFont boldSystemFontOfSize:42.f];
titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[titleLabel sizeToFit];
UILabel *subtitleLabel = [[UILabel alloc] init];
subtitleLabel.text = subtitle;
subtitleLabel.font = [UIFont systemFontOfSize:24.f];
subtitleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[subtitleLabel sizeToFit];
// Create gradient
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = titleLabel.bounds;
NSMutableArray *cgcolors = [NSMutableArray new];
for (int i = 0; i < colors.count; i++) {
cgcolors[i] = (id)colors[i].CGColor;
}
gradient.colors = cgcolors;
gradient.locations = #[#0, #1];
UIView *gradientView = [[UIView alloc] init];
[gradientView.layer addSublayer:gradient];
gradientView.maskView = titleLabel;
// Stack
UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:#[gradientView, subtitleLabel]];
stackView.alignment = UIStackViewAlignmentLeading;
stackView.axis = UILayoutConstraintAxisVertical;
stackView.distribution = UIStackViewDistributionEqualCentering;
stackView.spacing = 0;
stackView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:stackView];
[NSLayoutConstraint activateConstraints:#[
[stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:25],
[stackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
[stackView.heightAnchor constraintEqualToConstant:titleLabel.frame.size.height + subtitleLabel.frame.size.height],
[gradientView.widthAnchor constraintEqualToConstant:titleLabel.frame.size.width],
[gradientView.heightAnchor constraintEqualToConstant:titleLabel.frame.size.height]
]];
}
return self;
}
The problem is that your gradientView has no intrinsic content size.
Try changing your constraints to this:
[NSLayoutConstraint activateConstraints:#[
[stackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:25],
[stackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
// shouldn't need to set a height anchor on the stackView
//[stackView.heightAnchor constraintEqualToConstant:titleLabel.frame.size.height + subtitleLabel.frame.size.height],
[gradientView.widthAnchor constraintEqualToConstant:titleLabel.frame.size.width],
[gradientView.heightAnchor constraintEqualToConstant:titleLabel.frame.size.height],
]];

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];
}

CGRect intersection from child to self

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.

Activity Indicator while loading images inside UIScrollView

I have UIScrollView that contains images from the server.
I should put Activity Indicator while the image is currently loading.
UIScrollView contains dynamic number of images from the server.
May I know how can I add activity indicators on each page while the image is loading and remove once image is loaded.
Here's my code to retrieve images:
NSDictionary *items = [NSDictionary dictionaryWithObject:dictInfo forKey:#"images"];
imageList = [items objectForKey:#"images"];
NSArray *img = [imageList objectForKey:#"list"];
NSInteger imgCount = [img count];
buttonArray = [[NSMutableArray alloc] init];
for (int i=0; i<imgCount; i++) {
NSDictionary *imgDict = [img objectAtIndex:i];
// REQUEST FOR IMAGES
NSString *imgPath = [imgDict objectForKey:#"image_slot"];
NSString *imgURL = imgPath;
__block ASIHTTPRequest *requestImage = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:imgURL]];
[requestImage setCompletionBlock:^{
imgView = [UIImage imageWithData:[requestImage responseData]];
if (imgURL.length) {
[pendingRequests removeObjectForKey:imgURL];
}
scrollView.userInteractionEnabled = YES;
scrollView.exclusiveTouch = YES;
scrollView.canCancelContentTouches = YES;
scrollView.delaysContentTouches = YES;
scrollView.bounces = NO;
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
SWTUIButton *imgBtn = [[SWTUIButton alloc] initWithFrame:frame];
imgBtn.url = [requestImage.userInfo objectForKey:#"rURL"];
[imgBtn setImage:imgView forState:UIControlStateNormal];
imgBtn.backgroundColor = [UIColor clearColor];
[imgBtn addTarget:self action:#selector(buttonpushed:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:imgBtn];
[buttonArray addObject:imgBtn];
[imgBtn release];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * img.count, self.scrollView.frame.size.height);
}];
I highly suggest you use NINetworkImageView from https://github.com/jverkoey/nimbus project.
It's very light and useful.
It has a delegate method to let you know when an image is loaded.
What you basically need to do is:
1. create an NINetworkImageView for each page, just like you do with UIImageView, and call set
NINetworkImageView* networkImageView = [[[NINetworkImageView alloc] initWithImage:initialImage]
autorelease];
networkImageView.delegate = self;
networkImageView.contentMode = UIViewContentModeCenter;
[networkImageView setPathToNetworkImage:
#"http://farm3.static.flickr.com/2484/3929945380_deef6f4962_z.jpg"
forDisplaySize: CGSizeMake(kImageDimensions, kImageDimensions)];
https://github.com/jverkoey/nimbus/tree/master/examples/photos/NetworkPhotoAlbums
the add the indicator to the networkImageView as a subview.
implement the delegate as follows:
-(void)networkImageView:(NINetworkImageView *)imageView didLoadImage:(UIImage *)image {
[imageView removeAllSubviews];
}
the end result would be a much smaller code for doing the same thing.

how to remove the shadow for the label added to pie plot using core plot libraru in iphone sdk

I had added shadow for pie plot but I'm getting shadow for the label data also. I want to remove that shadow. Please help me.
Thanks in advance.
piePlot.dataSource = self;
piePlot.pieRadius = 65.0;
piePlot.pieInnerRadius = 35.0;
piePlot.shadowColor = [[UIColor blackColor]CGColor];
piePlot.shadowRadius = 3.0;
piePlot.shadowOffset = CGSizeMake(8,-3);
piePlot.shadowOpacity = 1.0;
piePlot.identifier = #"Current Year Credits By Type";
piePlot.startAngle = M_PI_4;
piePlot.sliceDirection = CPTPieDirectionClockwise;
piePlot.borderLineStyle = [CPTLineStyle lineStyle];
piePlot.sliceLabelOffset = 10.0;
-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index
{
CPTTextLayer *newLayer = nil;
static CPTMutableTextStyle *whiteText = nil;
if ( !whiteText )
{
whiteText = [[CPTMutableTextStyle alloc] init];
whiteText.color = [CPTColor blackColor];
}
if ( [plot isKindOfClass:[CPTPieChart class]] )
{
NSString *str = [NSString stringWithFormat:#"%#",[pieChartData1 objectAtIndex:index]];
newLayer = [[[CPTTextLayer alloc] initWithText:str style:whiteText] autorelease];
}
return newLayer;
}
Use Core Plot's CPTShadow class instead of the CALayer shadow properties.
CPTMutableShadow *blackShadow = [CPTMutableShadow shadow];
blackShadow.shadowOffset = CGSizeMake(8,-3);
blackShadow.shadowColor = [CPTColor blackColor];
piePlot.shadow = blackShadow;