Multiple UIView instance doesn't work
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.
开发者_如何学GoWhen 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?
That's because self.accelerometer.delegate = self;
is changing the sharedAccelerometer
's delegate and only the last assignment will have effect.
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.
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;
}
精彩评论