0

I implemented UIdynamics for objects (views) bouncing around the screen. On the simulator this works flawlessly, but but when testing on an actual iphone, the boundaries don't work. I will post code if necessary but this seems to me like im missing something conceptually. Any tips or ideas?

additional details: the boundaries surround the screen and i have tested on both sizes of simulator and it works fine.

"bad" is the name of the view-- (also "screenWidth" and "screenHeight" have been defined as instance variables)

///left wall
badCollision = [[UICollisionBehavior alloc] initWithItems:@[bad]];
badCollision.collisionDelegate = self;
CGPoint pt1 = CGPointMake(0, 0);
CGPoint pt2 = CGPointMake(0, screenHeight);
[badCollision addBoundaryWithIdentifier:@"leftWall" fromPoint:pt1 toPoint:pt2];
[animator addBehavior:badCollision];

//right wall
badCollision = [[UICollisionBehavior alloc] initWithItems:@[bad]];
badCollision.collisionDelegate = self;
pt1 = CGPointMake(screenWidth, 0);
pt2 = CGPointMake(screenWidth, screenHeight);
[badCollision addBoundaryWithIdentifier:@"rightWall" fromPoint:pt1 toPoint:pt2];
[animator addBehavior:badCollision];

//top wall
badCollision = [[UICollisionBehavior alloc] initWithItems:@[bad]];
badCollision.collisionDelegate = self;
pt1 = CGPointMake(0, 0);
pt2 = CGPointMake(screenWidth, 0);
[badCollision addBoundaryWithIdentifier:@"topWall" fromPoint:pt1 toPoint:pt2];
[animator addBehavior:badCollision];

//bottom wall
badCollision = [[UICollisionBehavior alloc] initWithItems:@[bad]];
badCollision.collisionDelegate = self;
pt1 = CGPointMake(0, screenHeight);
pt2 = CGPointMake(screenWidth, screenHeight);
[badCollision addBoundaryWithIdentifier:@"bottomWall" fromPoint:pt1 toPoint:pt2];
[animator addBehavior:badCollision];

And here is what happens when "bad" hits one of the walls.

    NSLog(@"Wall Hit");
    UIPushBehavior *badForce = [[UIPushBehavior alloc] initWithItems:@[item] mode:UIPushBehaviorModeInstantaneous];
    UIView *itemView = (UIView*)item;
    itemView.backgroundColor = [UIColor redColor];
    [UIView animateWithDuration:0.3 animations:^{
        itemView.backgroundColor = [UIColor blueColor];
    }];
    int xneg = (int)drand48();
    if (xneg < .51)
        xneg = 1;
    else
        xneg = -1;
    int yneg = (int)drand48();
    if (yneg < .51)
        yneg = 1;
    else
        yneg = -1;
    double xSpeed = xneg*(drand48()+1)/20+.02;
    double ySpeed = yneg*(drand48()+1)/20+.02;
    badForce.pushDirection = CGVectorMake(xSpeed,ySpeed);
    badForce.active = YES;

Not even the print statement will show in the log

MingMan
  • 911
  • 1
  • 10
  • 31
  • your right, in retrospect this seems really vague. There are multiple views which draw 20x20 rectangles. These initiate with an instantaneous force applied in a random direction. there is no resistance, gravity, or friction applied to these views. I updated the code above to show the boundaries created for the view. I also added what happens on the collision event. – MingMan Mar 13 '14 at 22:06

1 Answers1

0

You seem to be behaving like you wanted to update an existing behavior (your badForce.active = YES), but you're creating a new push behavior every time. Do one or the other. If you're going to create a new push behavior every time, you have to add it to your animator every time. If you're going to create it once, then add it to your animator once, and then just update and activate it each time.

You probably want to create one push behavior, add it once, and update it again and again:

- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
    NSString *wallIdentifier = (id)identifier;
    NSLog(@"Wall Hit: %@", wallIdentifier);

    if (!self.push) {
        self.push = [[UIPushBehavior alloc] initWithItems:@[item] mode:UIPushBehaviorModeInstantaneous];
        self.push.active = NO;
        [self.animator addBehavior:self.push];
    }

    UIView *itemView = (UIView*)item;
    itemView.backgroundColor = [UIColor redColor];
    [UIView animateWithDuration:0.3 animations:^{
        itemView.backgroundColor = [UIColor blueColor];
    }];

    double weight = 0.5;
    double xSpeed = weight * (drand48() * 2.0 - 1.0); // rand number between -weight and weight
    double ySpeed = weight * (drand48() * 2.0 - 1.0); // rand number between -weight and weight

    if ([wallIdentifier isEqualToString:@"bottomWall"])
        ySpeed = -fabs(ySpeed);
    else if ([wallIdentifier isEqualToString:@"topWall"])
        ySpeed = fabs(ySpeed);
    else if ([wallIdentifier isEqualToString:@"leftWall"])
        xSpeed = fabs(xSpeed);
    else if ([wallIdentifier isEqualToString:@"rightWall"])
        xSpeed = -fabs(xSpeed);

    self.push.pushDirection = CGVectorMake(xSpeed,ySpeed);
    self.push.active = YES;
}

Note, I hope you forgive me for tweaking your pushDirection algorithm, but I inferred from your creating of the four walls (rather than the much easier process of defining the boundaries of the reference view to be the collision boundary) that you wanted the push vector to vary based upon which wall you happened to collide with. The above pushes down if you hit the top wall (and vice versa) and pushes right if you hit the left wall (and vice versa). But use whatever push vector algorithm you want.

The main observation is that you either want to add one push behavior and update it again and again, or you want to just add new instantaneous push behaviors each time. But the above works on both simulator and device (and I'm honestly not clear why it worked on one and not the other for you; I don't see how your original code could have worked on either).

Rob
  • 415,655
  • 72
  • 787
  • 1,044