歩いてる風の棒人間を書いてみます。
(XcodeのiOS6 iPhone Simulatorで試しています。)
ポイント
・UIViewに肩と肘、腰と膝の情報を用意して、角度をタイマーで動かす
・線を足と同じくらいの速さで動かして、歩いている感をなんとなく。
サンプルコード
StickPerson.h
@interface StickPersonWalk : UIView
– (void)walk;
@end
StickPerson.m
#import “StickPersonWalk.h”
@interface StickPersonWalk() {
CGPoint head, shoulder, waist;
CGPoint lhand, rhand;
CGPoint lelbow, relbow;
CGPoint lfoot, rfoot;
CGPoint lknee, rknee;
int timeCounter;
}
@end
@implementation StickPersonWalk
– (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
CGSize s = self.bounds.size;
head = CGPointMake(s.width * 0.5, s.height * 0.1);
shoulder = CGPointMake(s.width * 0.5, s.height * 0.3);
waist = CGPointMake(s.width * 0.5, s.height * 0.6);
// hands
lelbow = CGPointMake(s.width * 0.4, s.height * 0.4);
lhand = CGPointMake(s.width * 0.3, s.height * 0.5);
relbow = CGPointMake(s.width * 0.6, s.height * 0.4);
rhand = CGPointMake(s.width * 0.7, s.height * 0.5);
// foots
lknee = CGPointMake(s.width * 0.4, s.height * 0.75);
lfoot = CGPointMake(s.width * 0.3, s.height * 0.9);
rknee = CGPointMake(s.width * 0.6, s.height * 0.75);
rfoot = CGPointMake(s.width * 0.7, s.height * 0.9);
}
return self;
}
– (void)drawRect:(CGRect)rect
{
[[UIColor blackColor] set];
[self drawStick];
}
– (void)drawStick
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, 5.0);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetLineJoin(ctx, kCGLineJoinRound);
float size = self.bounds.size.width;
CGContextFillEllipseInRect(ctx, CGRectMake(head.x – size*0.1, head.y, size*0.2, size*0.2));
CGContextMoveToPoint(ctx, head.x, head.y + size*0.1);
CGContextAddLineToPoint(ctx, shoulder.x, shoulder.y);
CGContextAddLineToPoint(ctx, waist.x, waist.y);
CGContextMoveToPoint(ctx, shoulder.x, shoulder.y);
CGContextAddLineToPoint(ctx, lelbow.x, lelbow.y);
CGContextAddLineToPoint(ctx, lhand.x, lhand.y);
CGContextMoveToPoint(ctx, shoulder.x, shoulder.y);
CGContextAddLineToPoint(ctx, relbow.x, relbow.y);
CGContextAddLineToPoint(ctx, rhand.x, rhand.y);
CGContextMoveToPoint(ctx, waist.x, waist.y);
CGContextAddLineToPoint(ctx, lknee.x, lknee.y);
CGContextAddLineToPoint(ctx, lfoot.x, lfoot.y);
CGContextMoveToPoint(ctx, waist.x, waist.y);
CGContextAddLineToPoint(ctx, rknee.x, rknee.y);
CGContextAddLineToPoint(ctx, rfoot.x, rfoot.y);
CGContextStrokePath(ctx);
}
– (void)walk
{
timeCounter++;
CGSize s = self.bounds.size;
// hand
int i = timeCounter % 50;
if (i > 25) {
i = 50 – i;
}
float angleLE = i * M_PI / 50.0 + M_PI * 0.2;
float lex = shoulder.x + s.width * 0.15 * cos(angleLE);
float ley = shoulder.y + s.width * 0.15 * sin(angleLE);
lelbow = CGPointMake(lex, ley);
float angleLH = angleLE – M_PI * 0.2;
float lhx = lelbow.x + s.width * 0.15 * cos(angleLH);
float lhy = lelbow.y + s.width * 0.15 * sin(angleLH);
lhand = CGPointMake(lhx, lhy);
i = (timeCounter + 25) % 50;
if (i > 25) {
i = 50 – i;
}
float angleRE = i * M_PI / 50.0 + M_PI * 0.2;
float rex = shoulder.x + s.width * 0.15 * cos(angleRE);
float rey = shoulder.y + s.width * 0.15 * sin(angleRE);
relbow = CGPointMake(rex, rey);
float angleRH = angleRE – M_PI * 0.2;
float rhx = relbow.x + s.width * 0.15 * cos(angleRH);
float rhy = relbow.y + s.width * 0.15 * sin(angleRH);
rhand = CGPointMake(rhx, rhy);
// foot
i = timeCounter % 50;
if (i > 25) {
i = 50 – i;
}
float angleLK = i * M_PI / 50.0 + M_PI * 0.15;
float lkx = waist.x + s.width * 0.2 * cos(angleLK);
float lky = waist.y + s.width * 0.2 * sin(angleLK);
lknee = CGPointMake(lkx, lky);
float angleLF = angleLK + M_PI * 0.2;
float lfx = lknee.x + s.width * 0.2 * cos(angleLF);
float lfy = lknee.y + s.width * 0.2 * sin(angleLF);
lfoot = CGPointMake(lfx, lfy);
i = (timeCounter + 25) % 50;
if (i > 25) {
i = 50 – i;
}
float angleRK = i * M_PI / 50.0 + M_PI * 0.15;
float rkx = waist.x + s.width * 0.2 * cos(angleRK);
float rky = waist.y + s.width * 0.2 * sin(angleRK);
rknee = CGPointMake(rkx, rky);
float angleRF = angleRK + M_PI * 0.2;
float rfx = rknee.x + s.width * 0.2 * cos(angleRF);
float rfy = rknee.y + s.width * 0.2 * sin(angleRF);
rfoot = CGPointMake(rfx, rfy);
[self setNeedsDisplay];
}
@end
ViewController.m
#import “ViewController.h”
#import “StickPersonWalk.h”
@interface ViewController () {
NSTimer *timer;
}
@end
@implementation ViewController
– (void)viewDidLoad
{
[super viewDidLoad];
StickPersonWalk *sw = [[StickPersonWalk alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[self.view addSubview:sw];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
[sw addGestureRecognizer:tap];
}
– (void)tap:(UIGestureRecognizer*)gr
{
// 人形を歩かせる
gr.view.tag = (gr.view.tag + 1) % 2;
[self start];
}
– (void)start
{
timer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(updateDisp:) userInfo:nil repeats:YES];
}
– (void)updateDisp:(NSTimer*)sender
{
// 人形を歩かせる
for (UIView *v in self.view.subviews) {
if (v.tag == 1) {
[(StickPersonWalk*)v walk];
}
}
// 背景の線を描画する
static int count = 0;
if (count % 50 == 0) {
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(360, –50, 2, 200)];
line.backgroundColor = [UIColor grayColor];
line.transform = CGAffineTransformMakeRotation(M_PI * 0.1);
line.tag = 2;
[self.view insertSubview:line atIndex:0];
UILabel *mark = [[UILabel alloc] initWithFrame:CGRectMake(330, 140, 40, 20)];
mark.text = [NSString stringWithFormat:@”%d”, count];
mark.tag = 2;
[self.view addSubview:mark];
}
count++;
// 線を移動させる
for (UIView *v in self.view.subviews) {
if (v.tag == 2) {
v.center = CGPointMake(v.center.x – 2, v.center.y);
if (v.center.x < 0) {
[v removeFromSuperview];
}
}
}
}
– (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end