How do you modify this sample code to stop Image Views from stacking? - iphone

http://developer.apple.com/library/ios/#samplecode/Touches/Introduction/Intro.html
I'm new to IOS development, and have been playing around with the IOS dev sample code, trying to learn how things work, etc... I came across this sample code (the classic version, not the gesture recognizers ver.) that does everything I'm looking for, except one thing. When the image views are dragged over another image view, they begin stacking up, and you have to double click the image to separate them.
I've spent forever trying to figure out how to make them not stack up. I think I have to store that a piece is getting being moved in an ivar, and stop it from getting the position of the other views... But I'm not sure how to go about doing it. If someone has the time to modify the sample code to not stack pieces, I'd really appreciate it! I'm dying to find out the solution after the forever I spent trying to do it!
I'll try to be a little specific with what I'm trying to do here... I've made 26 of these image views, making them each a letter of the alphabet. I have 13 image views in two rows. A-M & N-Z. Currently, if I drag the A tile down from the top row, moving it down to a "spelling area" I have to cross over the N-Z row. When I do, the "A" tile (image view) picks up any tile it hovers over. So if I drag the A straight down, it's going to pick up the N tile, because it's going to hover right over it, before getting down to the "spelling" area.
Thanks in advance for any help or direction you can give me!

Well you have this function in the sample code
// Checks to see which view, or views, the point is in and then calls a method to perform the closing animation,
// which is to return the piece to its original size, as if it is being put down by the user.
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then animate to that position.
if (CGRectContainsPoint([firstPieceView frame], position)) {
[self animateView:firstPieceView toPosition: position];
}
if (CGRectContainsPoint([secondPieceView frame], position)) {
[self animateView:secondPieceView toPosition: position];
}
if (CGRectContainsPoint([thirdPieceView frame], position)) {
[self animateView:thirdPieceView toPosition: position];
}
// If one piece obscures another, display a message so the user can move the pieces apart
if (CGPointEqualToPoint(firstPieceView.center, secondPieceView.center) ||
CGPointEqualToPoint(firstPieceView.center, thirdPieceView.center) ||
CGPointEqualToPoint(secondPieceView.center, thirdPieceView.center)) {
touchInstructionsText.text = #"Double tap the background to move the pieces apart.";
piecesOnTop = YES;
} else {
piecesOnTop = NO;
}
}
wich you can try to modify to
// Checks to see which view, or views, the point is in and then calls a method to perform the closing animation,
// which is to return the piece to its original size, as if it is being put down by the user.
-(void)dispatchTouchEndEvent:(UIView *)theView toPosition:(CGPoint)position
{
// Check to see which view, or views, the point is in and then animate to that position.
if (CGRectContainsPoint([firstPieceView frame], position)) {
[self animateView:firstPieceView toPosition: position];
}
if (CGRectContainsPoint([secondPieceView frame], position)) {
[self animateView:secondPieceView toPosition: position];
}
if (CGRectContainsPoint([thirdPieceView frame], position)) {
[self animateView:thirdPieceView toPosition: position];
}
// If one piece obscures another, display a message so the user can move the pieces apart
if (CGPointEqualToPoint(firstPieceView.center, secondPieceView.center) ||
CGPointEqualToPoint(firstPieceView.center, thirdPieceView.center) ||
CGPointEqualToPoint(secondPieceView.center, thirdPieceView.center)) {
if (firstPieceView.center.x == secondPieceView.center.x)
secondPieceView.center = CGPointMake(firstPieceView.center.x - 50, firstPieceView.center.y - 50);
if (firstPieceView.center.x == thirdPieceView.center.x)
thirdPieceView.center = CGPointMake(firstPieceView.center.x + 50, firstPieceView.center.y + 50);
if (secondPieceView.center.x == thirdPieceView.center.x)
thirdPieceView.center = CGPointMake(secondPieceView.center.x + 50, secondPieceView.center.y + 50);
touchInstructionsText.text = #"";
} else {
piecesOnTop = NO;
}
}
Let me know if it does what you want...

Related

Checking to see if point in child view is in parent view

I have the following set-up:
Where the light blue view, let's call it parentView, has a rectangular subview (the purple view) called childView. The user can use pan touches to rotate and stretch childView by putting their finger on the point exhibited by the red dot and pushing it or pulling it.
It's possible that the childView could be scaled small enough to that after the user is finished with its touches, the point denoted by the red dot would be inside of the parentView.
My goal is to create a method that can detect if the red point is in the parentView or not. I've written the following code:
CGPoint childViewRedPoint = CGPointMake(self.bounds.size.width, self.bounds.size.height / 2);
CGPoint rotatedChildViewRedPoint = CGPointApplyAffineTransform(childViewRedPoint, CGAffineTransformMakeRotation(self.rotateAngle));
CGPoint convertedChildViewRedPoint = [self convertPoint:rotatedChildViewRedPoint toView:self.superview];
if (CGRectContainsPoint(self.superview.bounds, convertedChildViewRedPoint))
{
return YES;
}
else
{
return NO;
}
First I find the red point as defined within the childView, then I rotate it by the amount that the view has been rotated, then I convert it to be in the parentViews coordinates.
The points I'm getting don't seem to make sense and this isn't working. Was wondering if anyone knows where I'm going wrong here? Am I not taking parentViews superview into account?
I am not 100% sure, but I think that convertPoint: already takes a rotation (or any other transformation) into account, so you only need:
CGPoint childViewRedPoint = CGPointMake(self.bounds.size.width, self.bounds.size.height / 2);
CGPoint convertedChildViewRedPoint = [self convertPoint:childViewRedPoint toView:self.superview];
if (CGRectContainsPoint(self.superview.bounds, convertedChildViewRedPoint))
...

Drag UIButton inside limits

I have searched around the web but haven't found a clear answer. I use a panGestureRecognizer to drag a slider button on the x axis, but I don't want to be able to drag if outside my slider track. I have managed to do some stuff, but it doesn't really work as it should. Here is my code
-(void) handleDrag:(UIPanGestureRecognizer*)panGestureRecognizer
{
if (panGestureRecognizer.state==UIGestureRecognizerStateBegan)
{
}
if (panGestureRecognizer.state==UIGestureRecognizerStateChanged)
{
CGPoint touchPoint=[panGestureRecognizer locationOfTouch:0 inView:self];
if (sliderButton.center.x > first.center.x-0.5f && sliderButton.center.x-0.5f < third.center.x && CGRectContainsPoint(sliderButton.frame, touchPoint) ) // if we are still in the slidertrack and the touch is on the sliderbutton
{
CGPoint newPoint=CGPointMake(touchPoint.x+0.5,sliderButton.center.y);
sliderButton.center=newPoint;
}
}
}
This is my slider
The first button is "Thu", the second one is "Fri" and the third is "Sat". I want my sliderButton to only move inside those boundaries.
Thank you.

implementing Static object on a moving scene

How to implement an 'menu' that seems like stuck to it's position? Here with stuck I meant to say either scene is moving or still it remain on it's on position. Which gives feel like it's on it's place. I am implementing it by moving it with scrolling scene, it works but behave absurdly, 'sometimes'.
Here is the code how am I creating menu:
resetPosition =[CCMenuItemImage itemFromNormalImage:#"position.png"
selectedImage:#"position_over.png"
disabledImage:#"disabled.png"
target:self
selector:#selector(reset)];
resetPosition.position =ccp(400, 300);
myresetMenu = [CCMenu menuWithItems:resetPosition, nil];
myresetMenu.position = ccp(0,0);
[[self parent] addChild:myresetMenu z:10];
[resetPosition setIsEnabled:NO];
And now code for moving the scene(when user trying to scroll the scene). Also I have moved the menu with scene, so it gives the effect that the menu is still with the scene:
if([touchArray count]==1)//scroll
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
moveLocation1 = [[CCDirector sharedDirector] convertToGL:location];
float diffX = beginLocation1.x - moveLocation1.x;
float diffY = beginLocation1.y - moveLocation1.y;
//NAVIGATION TOWARDS X AND Y WhenEver and how ever you want
if (abs(diffX) > abs(diffY))
{
CCLOG(#"yScrlFlag=%d",yScrlFlag);
if(diffX > 0)
{
xScrlFlag=1;
[self.parent runAction:[CCMoveTo actionWithDuration:round(-(-3112-self.parent.position.x)/650)
position:ccp((-3112-self.position.x),self.parent.position.y)]];
[resetPosition setIsEnabled:YES];
[resetPosition runAction:[CCMoveTo actionWithDuration:round(-(-3112-self.parent.position.x)/650)
position:ccp((3112+self.position.x+400),resetPosition.position.y)]];
}
else
{
xScrlFlag=0;
[self.parent runAction:[CCMoveTo actionWithDuration:(-self.parent.position.x/650)
position:ccp(0,self.parent.position.y)]];
//[resetPosition setIsEnabled:YES];
[resetPosition runAction:[CCMoveTo actionWithDuration:(-self.parent.position.x/650)
position:ccp(400,resetPosition.position.y)]];
}
}
else
{
if(diffY < 0)
{
yScrlFlag=1;
CCLOG(#"\n nodePosition.x=%f \n nodePosition.y=%f",nodePosition.x,nodePosition.y);
[self.parent runAction:[CCMoveTo actionWithDuration:(-(-300-self.parent.position.y)/650)
position:ccp(self.parent.position.x,(-self.position.y))]];
//[self.parent runAction:[CCMoveBy actionWithDuration:(-(-300-self.parent.position.y)/650)
// position:ccp(self.parent.position.x, -diffY)]];
[resetPosition setIsEnabled:YES];
//[resetPosition runAction:[CCMoveBy actionWithDuration:round(-(-300-self.parent.position.x)/650)
// position:ccp(resetPosition.position.x, (self.parent.position.y))]];
}
else
{
yScrlFlag=0;
[self.parent runAction:[CCMoveTo actionWithDuration:(-(-300-self.parent.position.y)/650)
position:ccp(self.parent.position.x,0)]];
//[resetPosition runAction:[CCMoveTo actionWithDuration:round(-(-300-self.parent.position.x)/650)
// position:ccp(resetPosition.position.x,300)]];
}
}
}
You don't specify how you create your menus and what are you doing with them, so my answer is pretty general...
The right approach to this, for me is having a UI layer where you put all your UI stuff (menus, buttons, etc.) and that you treat differently from your other, game layers. In other words, you give your UI layer a fixed position and then don't apply any actions or any other kind of transformations to it. It should stay pretty static this way.
Cocos2d offers its own classes to manage CCMenu, CCMenuItem, and CCLabel that allow you to build you UI easily. But, if you prefer, you could also try and integrate UIKit objects. Have a look at CCUIViewWrapper, if you really need it.
EDIT:
The idea about having a UI layer is the following in more detail:
you have a root layer acting as a container of all your layers;
one of those layers is the "game layer", which is pretty much what you have now;
another is the "ui layer";
touches and any kind of transformations are only applied to the "game layer", which move within the root layer without affecting the "ui layer".
There is a nice tutorial about this in "Learn Game Development with Cocos2D" by Steffen Itterheim. This book is fantastic if you want to learn several nifty approaches to your cocos2d game. The tutorial I am talking about is available in code form on Steffen's site. You can dowload it from this page and look into chapter 5 "Scene and Layers" example, specifically starting from ScenesAndLayers04, where you will find the 'MultiLayerScene.h/m` classes.
I had a bit of trouble with this a while back. I had been trying to have UI elements that did not get lost when the camera moved. What I ended up doing was adding a CCParallaxNode as a child and setting the parallax ratio to ccp(0.0, 0.0) on everything I put on it. That way the scene can move around but my UI layer stays in place. I'm not sure if that's the best way to do it, but I'm a dirty hack kind of programmer :)
#sergio has the right idea.
With your code though. Have it in a layer all to itself and then on the touch action move it like you are already and just reset its position when you take the action to bring the menu back up again.

Detecting screen edges when moving UIImageView

I currently have a UIImageView which I can move/drag around the view.
How does on detect for the edge of the screen when the image moves and stop the image from being able to be moved out of the screens view?
You can find the rectangle of the UIImageView in the coordinates of your (outermost) view using
CGRect r = [iv convertRect:iv.bounds toView:self.view];
Then it's a matter of checking if r goes out of bounds, e.g. like this:
CGRect i = CGRectIntersect(r,self.view.bounds);
if ( CGRectIsNull(i) )
{
NSLog(#"way out of bounds");
} else if ( !CGRectEqualToRect(i,r) ) {
NSLog(#"partly out of bounds");
} else {
NSLog(#"self.view envelopes imageview");
}
Of course, this should be put in your dragging code, with the NSLog() statements replaced with appropriate handling (e.g. by only updating location in the last case, or by translating the rect back into view if needed)

UIImage collision effect...??? Iphone

I need a way to create a collide effect, without the actual collision between the two images. Let me explain in more detail... If I have one fixed image and one image that is moving both images are on the same x coordinate at different positions. Basically I want the images appear to be colliding.I would want to run a check on the moving image like this...
If (front of moving image is clear)
{[move forward];}
else
{[stop];}
How would I implement this in code??? So that right before the moving image collides into the fixed image it stops, so that they appear to have collided.This check would also be running on a 1/60 NSTimer.
Any advice is welcome. Thank you.
Assuming the object is moving from the left
#define PIXELS_PER_FRAME 1
-(CGFloat) getCurrentX:(UIImage*)image
{
return image.frame.origin.x + image.frame.size.width;
}
-(void) moveImageToStableImage
{
CGFloat xTarget = stableImage.frame.origin.x;
if([self getCurrentX:movingImage] < xTarget)
{
movingImage.frame.origin.x += PIXELS_PER_FRAME;
[self performSelector:#selector(moveImageToStableImage) withObject:nil afterDelay:1.0/60];
}
}
But truth be told in this situation you would probably just be better off using an animation