Well here is my problem:
I have two images : flakeImage and ViewToRotate. What I want is that if flakeImage touches ViewToRotate, ViewToRotate.alpha=0.5; but when FlakeImage appears on the screen ViewToRotate.alpha=0.5; without touching it. I think it's a problem with my view beacause I have :
UIImageView* flakeView = [[UIImageView alloc] initWithImage:flakeImage];
here is the code :
UIImageView* flakeView = [[UIImageView alloc] initWithImage:flakeImage];
// use the random() function to randomize up our flake attributes
int startY = round(random() % 320);
// set the flake start position
flakeView.center = CGPointMake(490, startY);
flakeView.alpha = 1;
// put the flake in our main view
[self.view addSubview:flakeView];
[UIView beginAnimations:nil context:flakeView];
// set up how fast the flake will fall
[UIView setAnimationDuration:7 ];
// set the postion where flake will move to
flakeView.center = viewToRotate.center;
// set a stop callback so we can cleanup the flake when it reaches the
// end of its animation
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
How can I solve this please ?
if someone could help me it would be very cool.
I have a bit of sophomoric experience with this, having written http://itunes.apple.com/us/app/balls/id372269039?mt=8. If you check that app out, you will see a bit of the same problem. This topic is a pretty deep rabbit hole. WHen I started that app, I didn't even know how to write a decent game loop. You will need that first because you need to do precise time-step calculations. AFA the collisions, you update your model and view separately, so if you update the model and objects overlap, you need to back them up until they don't collide and then update your view with the result. If you plan to have a lot of colliding objects, you may hit a wall using UIViews. To complicate things more, if your objects are round, CGRectIntersectsRect won't exactly work. That complicates the math a bit, but it's not too bad. With my app, I found it quite difficult to get the physics to look realistic. THe problem became that ball A and B overlap, so you back them up, then they now intersect other balls, etc, etc. This link is a good starting point, but there are quite a few examples of code out there that "almost" work.
CGRect has a intersection function. The frames of UIViews are CGRects.
if (CGRectIntersectsRect(view1.frame, view2.frame) == 1)
NSLog(#"The views intersect");
else
NSLog(#"The views do not intersect");
The problem I foresee is that if the rects have lots of whitespace, they will appear to intersect before they actually touch
Secondly, you should switch up to block animations. It's strongly encouraged
UIImageView* flakeView = [[[UIImageView alloc] initWithImage:flakeImage] autorelease];
// use the random() function to randomize up our flake attributes
int startY = round(random() % 320);
// set the flake start position
flakeView.center = CGPointMake(490, startY);
flakeView.alpha = 1;
// put the flake in our main view
[self.view addSubview:flakeView];
[UIView animateWithDuration:.7
animations:^ {
// set the postion where flake will move to
flakeView.center = viewToRotate.center;
};
Did this all from memory, no idea if there are errors.
Circular Collision:
a^2 + b^2 < c^2 means they collide
if(pow(view2.frame.origin.x - view1.frame.origin.x, 2) +
pow(view2.frame.origin.y - view1.frame.origin.y, 2) <
pow(view1.frame.size.width/2, 2))
{
//collision
}
else
{
//no collision
}
Again, all from memory, check for errors on your own
Related
I've created an app where images fall from the sky and I have to "catch" them on the bottom with a user-moveable basket. I put the falling images and the basket image in CGRectMake frames and used CGRectIntersectsRect to detect for collisions. However, it's not detecting every collision. For example, I'll have visually "caught" 10 objects, the two frames definitely intersected, but it will only say I caught 2. What am I doing wrong?
Here is the code for the bucket:
(void)viewDidLoad
{
[super viewDidLoad];
basketView = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:#"bucket.png"]];
basketView.frame = CGRectMake(130.0, 412.0, 30.0, 30.0);
[self.view addSubview:basketView];
}
Here is the falling object and collision code:
- (void)onTimer
{
UIImageView* appleView = [[UIImageView alloc] initWithImage:appleImage];
int applePosition = round(random() % 320); //random starting x coord
double scale = 1 / round(random() % 100) + 1.0; //random apple size
double speed = 1 / round(random() % 100) + 1.0; //random apple speed
appleView.frame = CGRectMake(applePosition, -100.0, 25.0 * scale, 25.0 * scale);
[self.view addSubview:appleView];
[UIView beginAnimations:nil context:(__bridge void *)(appleView)];
[UIView setAnimationDuration:3 * speed];
appleView.frame = CGRectMake(applePosition, 500.0, 25.0 * scale, 25.0 * scale);
// Test for landing in bucket
if (CGRectIntersectsRect(basketView.frame, appleView.frame)) {
collision++;
printf("%i\n", collision);
[appleView removeFromSuperview];
}
}
EDIT: I made the basket huge, and now I'm getting spammed numbers and no apples are showing up. So I'm assuming that it's only checking for intersection with the apple at its starting point, not during the actual animation. How can I make it check for intersection DURING the animation?
Obviously if your timer function spawns new objects, the test will be done exactly after the creation of the object, so if the object is not actually created in the basket, your hit test will always be negative.
Now, you need another timer which will test for collisions every 10th of a sec or so (depending on how fast you move your objects, this could be more or less). An even better option (form the performance point of view) is to use CADisplayLink which works pretty much like a timer only it allows you to synchronise your tests to the refresh rate of the display.
In my app I want to move a little UIImageView with inside a .png; this is a little insect and I want to simulate his flight. At example I want that this png do when it move an inverted eight as the infinite simbol ∞
You may use CoreAnimation. You can subclass a view, create a subview for the insect, and then assign an animation to it, following a defined path.
Your UIImageView could be animated. If it's a fly, you can do a few frames for wing moves:
NSArray *images = [NSArray arrayWithObjects:..., nil];
insect.animationImages = images;
insect.animationDuration = ??;
insect.animationRepeatCount = 0;
[insect startAnimating];
Then set an init frame for the insect:
insect.frame = CGRectMake(-120, 310, [[images objectAtIndex:0] size].width, [[images objectAtIndex:0] size].height);
And then define the path:
CGMutablePathRef aPath;
CGFloat arcTop = insect.center.y - 50;
aPath = CGPathCreateMutable();
CGPathMoveToPoint(aPath, NULL, insect.center.x, insect.center.y);
CGPathAddCurveToPoint(aPath, NULL, insect.center.x, arcTop, 240, -100, 490, 360);
CAKeyframeAnimation* arcAnimation = [CAKeyframeAnimation animationWithKeyPath: #"position"];
arcAnimation.repeatCount = HUGE_VALF;
[arcAnimation setDuration: 4.5];
[arcAnimation setAutoreverses: NO];
arcAnimation.removedOnCompletion = NO;
arcAnimation.fillMode = kCAFillModeBoth;
[arcAnimation setPath: aPath];
CFRelease(aPath);
[insect.layer addAnimation: arcAnimation forKey: #"position"];
I leave how to do the infinite loop path up to you :)
Hope it helps!
Normally, if you were to be moving things around, I'd suggest using [UIView animate...]. However, you want something to move on a complex, curvy path. So instead, I'd suggest coming up with an equation that gives the (x,y) for the insect as a function of time, and then start an NSTimer with a fairly small time interval, and every time you get an update, move the insect (perhaps using [UIView animate...]).
Another way to go is to use a 2-d animation framework such as cocos2d - then, you can get an 'update' call linked to the frame refresh rate, inside of which you update the position of your insect using the same equation as from above.
This has been asked before, but there is no sample code to be found on stackoverflow and no proper solutions as far as I'm aware. I have a solution, but it looks crap. I'd be grateful for any input and modifications to get a more realistic 3D door open / book cover animation.
Aim is to have an animation between UIViewControllers so that you get the effect as if you were opening a door or a book cover. ViewController 2 is static and in the background. Above it you place ViewController 1 which covers ViewController 2. The animation will open ViewController 1 (like a hardcover book) and reveal ViewController 2 (your first page so to say, or whatever is behind the door).
First thing to note is that you can't do this with an UINavigationController as it is difficult to overwrite the custom animations. A proper tutorial on how to set up our two ViewControllers can be found here: ViewController Animations
So once everything is setup, here is my custom animation which looks crap. It basically looks as if you are squeezing the door / cover of the book to the left. There is no 3D feel to it, I'm afraid. Any suggestions of how to make this better would be welcome:
-(void)openDoorTo:(UIViewController *)aController duration:(float)aDuration {
[aController viewWillAppear:YES];
[activeController viewWillDisappear:YES];
[self.view insertSubview:aController.view belowSubview:activeController.view]; // so that it is below activeController
[aController viewDidAppear:YES];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:aDuration];
aController.view.transform = CGAffineTransformMakeTranslation(0,0);
CATransform3D _3Dt = CATransform3DIdentity;
_3Dt = CATransform3DTranslate(_3Dt, -320, 0, 0);
_3Dt = CATransform3DRotate(_3Dt, M_PI * 1.5, 0.0, 1, 0.0);
_3Dt = CATransform3DTranslate(_3Dt, 320, 0, 0);
activeController.view.layer.transform = _3Dt;
[UIView commitAnimations];
[self performSelector:#selector(animationDone:) withObject:aController afterDelay:aDuration];
}
I think the main problem is that I don't really know how to handle CATransform3DTranslate and CATransform3DRotate.
Here are some posts on this, but I can't really see how to apply them to a 3D Door opener:
3D Door - but Axis in the middle
3D Unfolding
You have to apply a little trick to get 3D to work:
CATransform3D _3Dt = CATransform3DIdentity;
_3Dt.m34 = 1.0 / -1000;
This creates perspective transform. 1000 represents the distance from the viewer to the objects (you can experiment with this value to get a smooth look).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
problem with collision of two images
HI everyone I'm french so scuse me for my english: SO I have two images(flakeView and viewToRotate) one that is moving, the other static in the center of the screen.What I want is : if flakeView and viewToRotate collide : do something. But the problem is that they intersects before they actually touch and I don't know where is the problem.
here is the code:
UIImageView *flakeView = [[UIImageView alloc] initWithImage:flakeImage];
// use the random() function to randomize up our flake attributes
int startX = round(random() % 480);
// set the flake start position
flakeView.center = CGPointMake(startX, -20.0);
flakeView.alpha = 1;
CGRect frame = CGRectMake(startX, -20.0, 30, 30);
flakeView.frame = frame;
// put the flake in our main view
[self.view addSubview:flakeView];
[UIView beginAnimations:nil context:flakeView];
// set up how fast the flake will fall
[UIView setAnimationDuration:7 ];
// set the postion where flake will move to
flakeView.center = viewToRotate.center;
// set a stop callback so we can cleanup the flake when it reaches the
// end of its animation
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
if (CGRectIntersectsRect(flakeView.frame, viewToRotate.frame) == 1){
//do something
}
}
How can I solve this please ?
Are you saying that CGRectIntersectsRect is true before the images touch?
If the graphic within the UIImageView is smaller than the frame the UIImageViews will, in fact, touch and even intersect before the visible images touch. I wonder if that's your problem.
If so, the solution would be to use as much of the frame as possible.
The other condition is that you have a non-rectangular shape inside your UIImageView. If you have the image of circle then CGRectIntersectsRect can return true when the circles are not touching (but their frames do).
The solution to the above is to either supplement CGRectIntersectsRect with code to check the bounds of the image being portrayed or to create your own collision detection code (my preference) to deal with the unique cases surrounding your shape.
I'm trying to make a slot machine animation where the reels spin. to do this, I'm using drawRect to draw images in a custom class that inherits from UIView. I'm using an nstimer to update the position of the images and calling [self setNeedsDisplay] to update the drawing. In the simulator, it looks very good, however, on the device, it is very laggy. I was wondering if i'm doing something wrong with my method of drawing or is there any better solutions.
- (void)drawRect:(CGRect)rect
{
[image1 drawInRect:CGRectMake(0, image1Position, 98, 80)];
[image2 drawInRect:CGRectMake(0, image2Position, 98, 80)];
[image3 drawInRect:CGRectMake(0, image3Position, 98, 80)];
}
- (void)spin
{
// move each position down by 10 px
image1Position -= MOVEMENT;
image2Position -= MOVEMENT;
image3Position -= MOVEMENT;
// if any of the position <= -60 reset to 180
if(image1Position < -50)
{
image1Position = 180;
}
if(image2Position < -50)
{
image2Position = 180;
}
if(image3Position < -50)
{
image3Position = 180;
}
[self setNeedsDisplay];
}
-(void)beginSpinAnimation
{
timer = [NSTimer scheduledTimerWithTimeInterval:SCROLL_TIME target:self selector:#selector(spin) userInfo:self repeats:YES];
}
My CoreAnimation Attempt with UIScrollView:
- (void) spinToNextReel
{
int y = self.contentOffset.y + 80;
// if the current >= last element reset to first position (-30)
if(y >= (80 *(elementCount+1) - 30))
{
y = -30;
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:SCROLL_TIME];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
self.contentOffset = CGPointMake(0, y);
[UIView commitAnimations];
if (!isSpinning && targetY == y)
{
NSLog(#"target is %d, y is %d", targetY, y);
if(timer)
{
[timer invalidate];
timer = nil;
}
[self playSound];
}
}
I would say research into CoreAnimation. It is made to do what you want to do here. It'll be much faster than what you are doing here.
As for it being slow, calling drawInRect isn't the fastest thing in the world. What is SCROLL_TIME?
You want to use CoreAnimation, it will be a lot easier, and more efficient. Having said that, if you insist on trying to manually animate this way you are doing a couple of thing wrong:
Do not attempt move a constant amount on fixed intervals, timer events can be delayed, and if they are that will result in your animation being uneven, since you are moving a constant amount per event, not per time interval. You should record the actual timestamp every time you animate, compare it to the previous timestamp, and move an appropriate number of pixels. This will result in even amounts of movement even if the events are delayed (effectively you will being dropping frames).
Do not use an NSTimer, use a CADisplayLink. That will tie your drawing to the native refresh rate of the system, and synchronize it with any other drawing that is going on.
I know I said it already, but learn and use CoreAnimation, you will be much happier.