XCODE: collision between left part of an image and another image - xcode

I´m developing a game in which the player moves a toothbrush along the screen (dragging it). I want it to react when the left side of the toothbrush(the part of the toothpaste) touches another image(teeth) to "clean it". I've tried the next code but i dont get the best result,because the teeth reacts with the hole image of the toothbrush, even with the handle. I think the problem is the ".center"command. After searching in internet, i havent seen anything.
I would really appreciate your help.
#synthesize toothbrush, teeth;
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *myTouch =[[event allTouches]anyObject];
toothbrush.center=[myTouch locationInView:self.view];
[self collision];
}
-(void)collision {
if (CGRectIntersectsRect(toothbrush.frame, teeth.frame)) {
cont++; //when the two images collide, the "cont" variable increases its value
mensaje.text=[[NSString alloc]initWithFormat:#"%d",cont];
}

Related

NSScrollView and manually setting the content offset while scrolling

I am trying to build an endless NSScrollView, i.e. a scroll view that can scroll infinitely in either direction. This is achieved by having a scroll view with fixed dimension which is 'recentered' once it gets too close to either edge, and keeping track of an additional endless offset that is updated when recentering. Apple even demonstrated this approach in a WWDC video for iOS, if I recall correctly.
On iOS everything is working. I perform the recentering logic in -scrollViewDidScroll: and it even works when the scrolling motion is decelerating without breaking the deceleration.
Now for the Mac version. Let me tell you that I'm fairly new to Mac development, so I may simply not have performed these operations in the correct places. I currently have the recentering logic in -reflectScrolledClipView:. When I perform the move operation immediately, however, the scroll view jumps exactly twice as far as I want it to (in this case, to 4000). If I delay the method slightly, it works just as expected.
- (void)reflectScrolledClipView:(NSClipView *)cView
{
[self recenteringLogic];
[super reflectScrolledClipView:cView];
}
- (void)recenteringLogic
{
CGFloat offset = self.documentVisibleRect.origin.y;
if (offset > 6000) {
// This makes the scroll view jump to ~4000 instead of 5000.
[self performSelector:#selector(move) withObject:nil];
// This works, but seems wrong to me
// [self performSelector:#selector(move) withObject:nil afterDelay:0.0];
}
}
- (void)move
{
[self.documentView scrollPoint:NSMakePoint(0, 4000)];
}
Any ideas on how I could achieve the behavior I want?
Try this:
- (void)scrollWheel:(NSEvent *)event {
[super scrollWheel:event];
[self recenteringLogic];
}
- (void)recenteringLogic
{
NSRect rect = self.documentVisibleRect;
if (rect.origin.y > 6000) {
rect.origin.y = 4000;
[self.contentView setBounds:rect];
}
}
reflectScrolledClipView seemed to be clashing with scrollToPoint somehow, and it caused a stack overflows when used with the [self.contentView setBounds:rect]; method of scrolling.
I ended up working with [self performSelector:#selector(move) withObject:nil afterDelay:0.0]; and haven't encountered any serious issues with it, despite it seeming a little wrong.

Cocos2d: Drawing on a UIImageView causes weird line jumps

I am implementing a CCLayer subclass that houses 2 UIImageViews. The views and layer are all the same size: I initialized the UIImageViews with the same frame, and set the contentSize of the layer to be the frame as well. Everything is working fine, but it seems as though something is going haywire with the first point when drawing. When the image is just tapped there is no line jump, but when I attempt to draw a stroke, as soon as I move my finger, the start of the line jumps down randomly(so in this screenshot I am drawing from left to right except for bottom-left line). I am not sure where I am going wrong in my code:
//_drawImageView is the UIImageView I am drawing in.
#pragma mark - Touch Methods
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
penStroked = NO;
_prevPoint = [touch locationInView:[[CCDirector sharedDirector]view]];
CGRect rect = self.boundingBox;
if (CGRectContainsPoint(rect, _prevPoint)) {
return YES;
}
return NO;
}
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
penStroked = YES;
_currPoint = [touch locationInView:_drawImageView];
UIGraphicsBeginImageContext(self.contentSize);
[_drawImageView.image drawInRect:CGRectMake(0, 0, _drawImageView.frame.size.width, _drawImageView.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _prevPoint.x, _prevPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), _currPoint.x, _currPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), penSize);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), penColor.r, penColor.g, penColor.b, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
_drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[_drawImageView setAlpha: penOpacity];
UIGraphicsEndImageContext();
_prevPoint = _currPoint;
}
I was having a really hard time initially aligning the point at which the line would be draw n and the actual position of my finger, so that is why in the ccTouchBegan method the touch is taken from the CCDirector and in ccTouchMoved it is taken from the _drawImageView. This is the only way it seems to draw perfectly besides the initial wonky behavior.
The problem was definitely caused by the differing references for the touches. As I had said before though, it was the only way to have the line match the position my finger was in. I figured that the line jump was due to the line of code:
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), _prevPoint.x, _prevPoint.y);
The problem was that on the first go around, or the first time that the pen/finger is stroked, the previous point was referenced from the CCDirectors view while the current point was from the imageView. I created an int variable, that was incremented every time the pen was stroked and when penStrokedInt == 1 (first stroke), I corrected the _prevPoint to the WorldSpace using the current point coordinates:
_prevPoint = [self convertToWorldSpace:_currPoint];
which basically got rid of the very first point in the line. It's not the best solution, but now it works! Make sure to reset the penStrokedInt back to 0 when the ccTouchEnded.

AV Foundation: Difference between currentItem being ready to play, and -[AVPlayer readyForDisplay] property?

I'm running into a weird situation with my video player, the core code of which hasn't changed much from what worked in an earlier app I made. Here's the problem: I'm inserting a "_loadingLayer" (a CATextLayer that says the video is loading), and then observing the AVPlayer's currentItem's status property to figure out when to remove the "_loadingLayer" and replace it with my actual "_playerLayer". Here's my KVO code for that:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ((object == _playerLayer) && (_playerLayer.player.currentItem.status == AVPlayerItemStatusReadyToPlay)) {
[CATransaction setAnimationDuration:1.8];
_loadingLayer.opaque = NO;
if (_playerLayer.readyForDisplay) {
NSLog(#"Should be ready now.");
}
[self addPlayerLayerToLayerTree];
}
}
My problem is that the video is starting, but only the audio is playing -- the layer stays black. When I inserted the NSLog statement above, I found out why: Apparently although the currentItem's status is "AVPlayerItemStatusReadyToPlay", the player layer isn't actually readyForDisplay. This makes no sense to me -- it seems counterintuitive. Can someone please give me some guidance on this?
I was able to verify that _playerLayer is being added to the layer tree by setting its background color to red.
One other weird thing that I think might be related.... I've been seeing these messages in the debugger console:
PSsetwindowlevel, error setting window level (1000)
CGSSetIgnoresCycle: error 1000 setting or clearing window tags
Thanks in advance. This is a crosspost from the Apple Dev Forums.
We had a similar problem and traced it to what I believe is a bug in iOS 5.1 (and maybe earlier versions). It is fixed in iOS 6.0. Since I couldn't find a solution to this anywhere, I'm writing a long writeup for future people that have this problem.
If the AVPlayerItem reports a status of AVPlayerStatusReadyToPlay before the AVPlayerLayer has been obtained then the AVPlayer will never report that it is readyForDisplay.
So when you do:
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
make sure that it's followed with:
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
and that you don't have much if any code in between the two.
I built a test rig to make it work 100% of the time or fail 100% of the time. Note that it can be tricky to see what's going on in your actual app since you will have different load times on the video and that will affect how quickly the playerItem reports AVPlayerStatusReadyToPlay.
If you want to test in your app, put this into a simple view. The below will not work (i.e. you'll hear audio but not see video) on iOS 5.1. If you switch loadPlayerLayer to instead be invoked at the end of loadPlayer, it will always work.
A follow on for future readers: A couple of player events can switch up this order and make you think it's working. They're red herrings though since they're inadvertently reversing the load order such that playerLayer is grabbed before AVStatusReadyToPlay. The events are: seeking the video, going to the home screen and then reactivating the app, the player switching to a different video/audio track inside an HLS video. These actions trigger AVStatusReadyToPlay again and thus make the playerLayer happen before AVStatusReadyToPlay.
Here's the test harness that uses Apple's test HLS video:
-(void)loadPlayer
{
NSLog(#"loadPlayer invoked");
NSURL *url = [NSURL URLWithString:#"https://devimages.apple.com.edgekey.net/resources/http-streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8"];
self.playerItem = [AVPlayerItem playerItemWithURL:url];
[self.playerItem addObserver:self forKeyPath:#"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerContext];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
}
-(void)loadPlayerLayer
{
NSLog(#"starting player layer");
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
[self.playerLayer addObserver:self forKeyPath:#"readyForDisplay" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:&kPlayerLayerContext];
[self.playerLayer setFrame:[[self view] bounds]];
[[[self view] layer] addSublayer:self.playerLayer];
}
-(void)observeValueForKeyPath:(NSString*)path ofObject:(id)object change:(NSDictionary*)change context:(void*) context
{
if(context == &kPlayerContext){
if([self.player status] == AVPlayerStatusReadyToPlay){
NSLog(#"Player is ready to play");
//Robert: Never works if after AVPlayerItem reports AVPlayerStatusReadyToPlay
if(!self.startedPlayerLayer){
self.startedPlayerLayer = YES;
[self loadPlayerLayer];
}
}
}
if(context == &kPlayerLayerContext){
if([self.playerLayer isReadyForDisplay] == YES){
NSLog(#"PlayerLayer says it's ready to display now");
[self playTheVideoIfReady];
}
}
}

How to detect when a user, and only a user scrolls an NSScrollView

Does anyone know a way to detect when an NSScrollView is scrolled by user input, and only user input)?
The reason I want to do this is because I have a NSScrollView with a contentView that is continuously increasing it's width. I want the NSScrollView to 'lock' onto the right hand end of the contentView (i.e. track it) if the user scrolls to the right hand end of the contentView and I want the 'lock' to be released when the user (and only the scrolls) scrolls aways from the right hand end.
The closest I had to getting to this to work was by observing the NSViewBoundsDidChangeNotification and changing a 'lock' variable, as shown here:
- (void)drawRect:(NSRect)dirtyRect
{
(...)
if (lockToEnd) {
NSLog(#"xAxisView at end");
NSPoint newScrollOrigin;
newScrollOrigin.y = 0;
newScrollOrigin.x = [self frame].size.width - [[self enclosingScrollView] bounds].size.width;
[self scrollPoint:newScrollOrigin];
}
}
-(void)SWXAxisViewDidScroll:(NSNotification *)note{
NSLog(#"XAxisDidScroll: %#",note);
if ([[[self enclosingScrollView] horizontalScroller] floatValue] > 0.97){
lockToEnd = YES;
} else {
lockToEnd = NO;
}
}
However, this was not appropriate because an NSViewBoundsDidChangeNotification is sent anytime the bounds are changed, and thus when the bounds of the contentView increase, the NSScroller reduces it's floatValue and my observing method is called. EVen if I set the NSScroller's floatValue to 1.0, it is reset to 0.0 when the bounds.size.width of the contentView first exceeds the bounds.size.width of the NSScrollView. Thus, I can't tell if the NSViewBoundsDidChangeNotification was sent because the user scrolled or because the contentView got wider.
I have considered subclassing NSScroller and using the mouseDown: and mouseDragged: methods to track user input and update my lock variable. However, my concern is that these methods will not be called if the user swipes their trackpad to scroll. Another smaller concern, which I think is probably unfounded, is that it might break the NSScrollView<->NSScroller relationship and I would have to re-implement a lot of scrolling features.
Have I missed a simpler way to do this? It seems like I should be able to do this because documents do it all the time? Are my concerns about subclassing NSScroller valid?

Enabling multi-touch in game?

I am creating a simple pong game in Xcode. I have a 2 player version and both paddles can be moved and function perfectly. The game is flawless except for the fact that you cannot move both paddles at the same time, rendering the 2 player mode useless.
How can I enable both paddles to be moved at the same time?
I've already tried selecting the "Multiple Touch" button in Interface Builder but it does nothing and im not quite sure it is even the correct route into enabling multi touch as I want it.
Also, my game is a View-Based Application if that matters.
Thanks!
EDIT: I mis-read the question. Added code snippet.
Here's the code I use to extract all touches when I get a touchesBegan event:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *touchesArray = [touches allObjects];
NSUInteger nNumTouches = [touchesArray count];
UITouch *touch;
CGPoint ptTouch;
for (int nTouch = 0; nTouch < nNumTouches; nTouch++)
{
touch = [touchesArray objectAtIndex:nTouch];
ptTouch = [touch locationInView:self.view];
// Do stuff with the touch
}
}
and similarly for touchesEnded and touchesMoved
From my experience (which isn't that much). You can create 2 UIViews for the 2 paddles, touching in one view will move one paddle, while touching in the other will move the other paddle. I hope this helps.
If you don't know how to split the views, you can simply make it identify 2 touches
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch1 = [[event touchesForView:zone1] anyObject];
UITouch *touch2 = [[event touchesForView:zone2] anyObject];
if (touch1)
touchOffset1 = paddle1.center.x - [touch1 locationInView:touch1.view].x;
if (touch2)
touchOffset2 = paddle2.center.x - [touch2 locationInView:touch2.view].x;
}
This you can use, it probably isn't the most productive, but it does work if you can't figure out how to split the touches.
self.view.multipleTouchEnabled = YES;
by default it is No

Resources