多重連結バネをやってみた
wonderflにあった面白いものをiPhone(iPad)用に書き直してみるシリーズ。
元ネタはここ。
MeshViewを作る。ViewController.viewにでもはりつけて表示すれば使えまする。
@interface MeshView : UIView { @private NSMutableArray *mi_ar; } @end
#import "MeshView.h" #import <QuartzCore/QuartzCore.h> @interface Pin : UIView { Pin *right_, *left_, *up_, *down_; } @property (nonatomic, assign) Pin *right, *left, *up, *down; + (NSArray *)directions; - (void)setup; - (void)resetWithLeft:(Pin *)left Right:(Pin *)right Up:(Pin*)up Down:(Pin *)down; @end @interface Mi : Pin { @private CGFloat k, t; CGFloat ax, ay, vx, vy; BOOL ignoreUpdate; } - (void)update; @end @implementation MeshView - (id)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { // Initialization code CGRect field = CGRectMake(0, 0, 320, 320); CGFloat dxy = 30; int w = field.size.width / dxy; int h = field.size.height / dxy; mi_ar = [[NSMutableArray alloc] init]; CGFloat sx = (field.size.width - dxy * (w - 1)) * .5; CGFloat sy = (field.size.height - dxy * (h - 1)) * .5; Pin *p; for (int j = 0 ; j < h; j++) { for (int i = 0; i < w; i++) { if (j == 0 || j == h - 1 || i == 0 || i == w - 1) { p = [[Pin alloc] initWithFrame:CGRectMake(0, 0, dxy, dxy)]; } else { p = [[Mi alloc] initWithFrame:CGRectMake(0, 0, dxy, dxy)]; } [p setup]; [self addSubview:p]; p.center = CGPointMake(sx + i * dxy, sy + j * dxy + 80); [mi_ar addObject:p]; } } for (int i = 0; i < [mi_ar count]; i++) { if (w - 1 < i && i < [mi_ar count] - w && i % w != 0 &&i % w != w - 1) { p = [mi_ar objectAtIndex:i]; [p resetWithLeft:[mi_ar objectAtIndex:i - 1] Right:[mi_ar objectAtIndex:i + 1] Up:[mi_ar objectAtIndex:i - w] Down:[mi_ar objectAtIndex:i + w]]; } } CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)]; displayLink.frameInterval = 2; [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; } return self; } // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextClearRect(ctx, rect); for (id m in mi_ar) { if ([m respondsToSelector:@selector(update)]) { [m update]; } } [[UIColor redColor] setStroke]; Pin *pn; for (Pin *p in mi_ar) { if ((pn = p.up) != nil && pn.up == nil) { CGContextMoveToPoint(ctx, p.center.x, p.center.y); CGContextAddLineToPoint(ctx, pn.center.x, pn.center.y); } if ((pn = p.left) != nil && pn.left == nil) { CGContextMoveToPoint(ctx, p.center.x, p.center.y); CGContextAddLineToPoint(ctx, pn.center.x, pn.center.y); } if ((pn = p.right) != nil) { CGContextMoveToPoint(ctx, p.center.x, p.center.y); CGContextAddLineToPoint(ctx, pn.center.x, pn.center.y); } if ((pn = p.down) != nil) { CGContextMoveToPoint(ctx, p.center.x, p.center.y); CGContextAddLineToPoint(ctx, pn.center.x, pn.center.y); } } CGContextStrokePath(ctx); } - (void)dealloc { [mi_ar release]; [super dealloc]; } @end @implementation Pin @synthesize right = right_, left = left_, up = up_, down = down_; static NSArray *directions; static UIColor *pinColor; + (NSArray *)directions { if (directions != nil) { return directions; } directions = [[NSArray alloc] initWithObjects:@"up", @"left", @"down", @"right", nil]; return directions; } + (UIColor *)color { if (pinColor != nil) { return pinColor; } pinColor = [[UIColor blueColor] retain]; return pinColor; } + (CGFloat)radius { return 10; } /* - (NSString *)description { return [NSString stringWithFormat:@"%@ %@ %@ %@", left_, right_, up_, down_]; } */ - (void)setup { CGRect rect = self.frame; CGFloat radius = [[self class] radius]; UIGraphicsBeginImageContext(rect.size); CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(ctx, CGRectMake(rect.size.width / 2 - radius / 2, rect.size.height / 2 - radius / 2, radius, radius)); [[[self class] color] setFill]; CGContextFillPath(ctx); UIImage *contents = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); self.layer.contents = (id)contents.CGImage; } - (void)resetWithLeft:(Pin *)left Right:(Pin *)right Up:(Pin *)up Down:(Pin *)down{ self.left = left; self.right = right; self.up = up; self.down = down; [self setup]; } @end @implementation Mi static UIColor *miColor; + (UIColor *)color { if (miColor != nil) { return miColor; } miColor = [[UIColor redColor] retain]; return miColor; } - (void)setup { [super setup]; ax = ay = vx = vx = 0; t = 0.04; k = 0.02; UIPanGestureRecognizer *gr = [[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)] autorelease]; [self addGestureRecognizer:gr]; } - (void)dealloc { for (UIGestureRecognizer *gr in self.gestureRecognizers) { [self removeGestureRecognizer:gr]; } [super dealloc]; } #pragma mark - #pragma mark pan action - (void)move:(UIPanGestureRecognizer *)gr { UIGestureRecognizerState state = [gr state]; if (state == UIGestureRecognizerStateChanged || state == UIGestureRecognizerStateBegan) { self.center = [gr locationInView:self.superview]; CGPoint translation = [gr translationInView:self.superview]; self.center = CGPointMake(self.center.x + translation.x, self.center.y + translation.y); [gr setTranslation:CGPointZero inView:self.superview]; } if (state == UIGestureRecognizerStateBegan) { ignoreUpdate = YES; } else if (state == UIGestureRecognizerStateEnded) { ignoreUpdate = NO; } } #pragma mark 0 #pragma mark update properties - (void)update { if (ignoreUpdate) { return; } CGFloat dx = 0, dy = 0; CGPoint center = self.center; /* Pin *pn; pn = left_; if (pn != nil) { dx += pn.center.x - center.x; dy += pn.center.y - center.y; } pn = right_; if (pn != nil) { dx += pn.center.x - center.x; dy += pn.center.y - center.y; } pn = up_; if (pn != nil) { dx += pn.center.x - center.x; dy += pn.center.y - center.y; } pn = down_; if (pn != nil) { dx += pn.center.x - center.x; dy += pn.center.y - center.y; } */ Pin *pn; NSArray *directions = [Pin directions]; for (NSString *direction in directions) { pn = [self valueForKey:direction]; if (pn == nil) { continue; } dx += pn.center.x - center.x; dy += pn.center.y - center.y; } ax = k * dx; ay = k * dy; vx += ax - vx * t; vy += ay - vy * t; self.center = CGPointMake(self.center.x + vx, self.center.y + vy); } @end