views:

294

answers:

3

Hi, I have subclass UIView class in a Bounce class with Accelerometer. This Bounce class show an image and move it on the screen. When the iPhone device is moved, this image Bounce on the screen.

When I create multiple instance, only last instance work properlty:

// in the MainViewController.m

Bounce *heart[100];


for(int i = 0; i < 10; i++) {
    rx = (arc4random() % 300) + 10;
    ry = (arc4random() % 300) + 10;
    NSLog(@"random %d %d", rx, ry);
    heart[i] = [[Bounce alloc] initWithPNG:@"Heart.png" 
                       position:CGPointMake(rx, ry) size:CGSizeMake(64, 64)];
    heart[i].velocity = CGPointMake(1.0, 1.0);
    [self.view addSubview: heart[i]];
}

This is the Bounce Class:

//
//  Bounce.h
//  iMakeLove
//
//  Created by Giovambattista Fazioli on 06/11/09.
//  Copyright 2009 Saidmade srl. All rights reserved.
//

#import <UIKit/UIKit.h>


@interface Bounce : UIView <UIAccelerometerDelegate> {

    CGPoint  position;
    CGSize  size;
    CGPoint  velocity;
    NSTimer  *objTimer;
    NSString *pngName;
    CGFloat  bounce;
    CGFloat  gravity;
    CGPoint  acceleratedGravity;
    CGPoint  lastTouch;
    CGPoint  currentTouch;
    BOOL  dragging;

    UIAccelerometer *accelerometer;

}



@property CGPoint position;
@property CGSize size;
@property CGPoint velocity;
@property(nonatomic,retain)NSString *pngName;
@property(nonatomic,retain)NSTimer *objTimer;
@property CGFloat bounce;
@property CGFloat gravity;
@property CGPoint acceleratedGravity;
@property CGPoint lastTouch;
@property CGPoint currentTouch;
@property BOOL dragging;

- (id)initWithPNG:(NSString*)imageName position:(CGPoint)p size:(CGSize)s;

- (void)update;
- (void)onTimer;
- (void)startPrevent;

@end

Implementation:

//
//  Bounce.m
//  iMakeLove
//
//  Created by Giovambattista Fazioli on 06/11/09.
//  Copyright 2009 Saidmade srl. All rights reserved.
//

#import "Bounce.h"

@implementation Bounce

@synthesize position, size;
@synthesize objTimer;
@synthesize velocity;
@synthesize pngName;
@synthesize bounce;
@synthesize gravity, acceleratedGravity;
@synthesize lastTouch, currentTouch;
@synthesize dragging;



- (id)initWithPNG:(NSString*)imageName position:(CGPoint)p size:(CGSize)s {

    if (self = [super initWithFrame:CGRectMake(p.x, p.y, s.width, s.height)]) {

     [self setPngName:imageName];
     [self setPosition:p];
     [self setSize:s];
     [self setBackgroundColor:[UIColor clearColor]];

     // Set default gravity and bounce

     [self setBounce:-0.9f];
        [self setGravity:0.5f];
     [self setAcceleratedGravity:CGPointMake(0.0, gravity)];
     [self setDragging:NO];

     UIImageView *prezzie = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, s.width, s.height)];

     prezzie.image = [UIImage imageNamed:imageName];

     [self addSubview:prezzie];

     [prezzie release];

     self.accelerometer = [UIAccelerometer sharedAccelerometer];
     self.accelerometer.delegate = self;

    }
    return self;
}

- (void)startPrevent {
    if (objTimer == nil) {
     objTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
    }
}


- (void)update {

    [self setNeedsDisplay];

    if(dragging) return;

    velocity.x += acceleratedGravity.x;
    velocity.y += acceleratedGravity.y;
    position.x += velocity.x;
    position.y += velocity.y;

    if(position.x + size.width >= 320.0) {
        position.x = 320.0 - size.width;
        velocity.x *= bounce;
    } else if(position.x <= 0.0) {
        velocity.x *= bounce;
    }

    if(position.y + size.height >= 480.0) {
        position.y = 480.0 - size.height;
        velocity.y *= bounce;
    } else if(position.y <= 0.0) {
        velocity.y *= bounce;
    }
    self.frame = CGRectMake(position.x, position.y, size.width, size.height);
}



- (void)onTimer {
    [self update];
}



- (void)drawRect:(CGRect)rect {

    // Drawing code

}

/* EVENTS */


- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    acceleratedGravity.x = acceleration.x * gravity;
    acceleratedGravity.y = -acceleration.y * gravity;
}



- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    // First, lets check to make sure the timer has been initiated

    if (objTimer == nil) {
     objTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 30.0 target:self selector:@selector(onTimer) userInfo:nil repeats:YES];
    }

    UITouch *touch = [touches anyObject];

    [self setCurrentTouch:[touch locationInView:self]];
    CGFloat dx = currentTouch.x - position.x;
    CGFloat dy = currentTouch.y - position.y;
    CGFloat dist = sqrt(dx * dx + dy * dy);

    if(dist < size.width) {
        [self setVelocity:CGPointMake(0.0, 0.0)];
     [self setDragging:YES];
    }
    [self setLastTouch:currentTouch];

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    [self setCurrentTouch:[touch locationInView:self]];
    [self setDragging:YES];
    [self setVelocity:CGPointMake(currentTouch.x - lastTouch.x, currentTouch.y - lastTouch.y)];
    [self setLastTouch:currentTouch];

}



- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self setDragging:NO];
}





- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Initialization code
    }
    return self;
}

- (void)dealloc {
    [super dealloc];
}


@end

Can you help me?

A: 

I believe that only the front-most view will get the acceleromter messages. You might want the accelrometer messages to be sent to your viewcontroller instead.

mahboudz
Very good idea... thanks...
Undolog
+2  A: 

That's because self.accelerometer.delegate = self; is changing the sharedAccelerometer's delegate and only the last assignment will have effect.

codelogic
A: 

What I might do here. (It may not be the best thing long term, but will fix the immediate problem) is this:

I'd make accelerated gravity a static variable shared among all instances of Bounce. This makes sence to me because in the real world (the one that we are simulating) Accelerated gravity would be the same for all the Bounces. (I'd also rename Bounce to something like BouncingView). I'd access that variable through a couple of class methods. Also, I'd make the accelerometer shared, and have its delegate method, a class method. Put this stuff in your class and it should work: (I'd test it but my development machine is at the Apple Store getting fixed.) Also, there are a couple syntax errors in the example code you posted.

  static CGCGPoint acceleratedGravity;
  static UIAccelerometer *accelerometer;

    -(void) init {
        /* Everything Else */
        self.accelerometer = [UIAccelerometer sharedAccelerometer];
        self.accelerometer.delegate = self;
        /*Everything Else */
    }

    +(CGPoint) acceleratedGravity {
        return acceleratedGravity;
    }

    +(void) setAcceleratedGravity:(CGPoint) _acceleratedGravity {
        acceleratedGravity = _acceleratedGravity;
    }

+ (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    acceleratedGravity.x = acceleration.x * gravity;
    acceleratedGravity.y = -acceleration.y * gravity;
}
Brad Smith
the + in the delegate method will move it from instance scope to class scope.
Brad Smith
Thanks... Syntax error where?
Undolog
Nothing Major, rx and ry were not delared in you main view controller's for loop. (at least not in the snippet) and in the Bounce class you are using self.accelerometer in the implementation, but you did not have a property declaration (only the variable) in the header and no @synthisize. Were you able to get your accelerometer issue sorted out?
Brad Smith