ハンマー投げみたいな感じで、くるくる回したViewを投げてみる

(XcodeのiOS6 iPhone Simulatorで試しています。)

ポイント

Box2dのjointを使いView二つをくっつける。

PanGestureで指を離したらViewが飛んでいくようにする。

( jointの削除で、ハンマーから手を離したような動きになる )

Box2d導入手順

次のアドレスからソースを取得

 svn checkout http://box2d.googlecode.com/svn/trunk/ box2d-read-only

1. Box2Dをプロジェクトに組み込む

  Xcodeメニューの File -> Add File

2. C++ で書く。Fileの拡張子を変更

 Box2dを使うソースの拡張子を mm に

3.  Box2Dを import できるように Search Pathを追加

 Build Settings (All) の Search Pathsのなかの Header Search Paths 

サンプルコード

#import “ViewController.h”

#import <Box2D/Box2D.h>

#import <QuartzCore/QuartzCore.h>

#define PTM_RATIO 16

@interface ViewController () {

    b2World *world;

    b2Body *box;

    b2Joint *joint;

    NSTimer *timer;

    UIView *ball;

    UIView *backScene;

    int ballThrow;

    UILabel *meter;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.bounds = CGRectMake(0, 0, 8000, self.view.bounds.size.height);

    

    [self ready];

}

– (void)clear

{

    // 初期化

    [timer invalidate];

    timer = nil;

    for (UIView *v in self.view.subviews) {

        [v removeFromSuperview];

    }

    for (UIView *v in self.view.window.subviews) {

        if (v != self.view) {

            [v removeFromSuperview];

        }

    }

    ball = nil;

    backScene = nil;

    meter = nil;

    world->DestroyBody(box);

    world = NULL;

    ballThrow = 0;

    self.view.center = self.view.window.center;

}

– (void)ready

{

    [self createBackGround];

    

    [self createPhysicsWorld];

    

    [self createBox];

    

    [self start];

}

– (void)reset

{

    [self clear];

    [self ready];

}

– (void) createBackGround

{

    CGRect rect = CGRectMake(0, 0, 8000, 400);

    backScene = [[UIView alloc] initWithFrame:rect];

    backScene.backgroundColor = [UIColor whiteColor];

    for (int i=0; i<80; i++) {

        UIView *v = [[UIView alloc] initWithFrame:CGRectMake(i*100, 0, 1, self.view.bounds.size.height)];

        v.backgroundColor = [UIColor lightGrayColor];

        [backScene addSubview:v];

    }

    [self.view addSubview:backScene];

}

– (void)createBox

{

    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(200, 200, 40, 40)];

    v.backgroundColor = [UIColor yellowColor];

    [self.view addSubview:v];

    [self addPhysicalBodyForView:v];

    

    UIView *v2 = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];

    v2.backgroundColor = [UIColor redColor];

    v2.center = CGPointMake(170, 170);

    [self.view addSubview:v2];

    [self jointView:v2];

    ball = v2;

    

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];

    [v addGestureRecognizer:pan];

}

– (void)createPhysicsWorld

{

    CGSize screenSize = CGSizeMake(8000, 310);

    

    b2Vec2 gravity;

    gravity.Set(0.0f, –9.81f);

    

    world = new b2World(gravity);

    world->SetContinuousPhysics(true);

    

    b2BodyDef groundBodyDef;

    groundBodyDef.position.Set(0, 0);

    b2Body *groundBody = world->CreateBody(&groundBodyDef);

    

    b2EdgeShape groundBox;

    

    groundBox.Set(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO, screenSize.height/PTM_RATIO));

    groundBody->CreateFixture(&groundBox, 0);

    

    groundBox.Set(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO, 0));

    groundBody->CreateFixture(&groundBox, 0);

    

    groundBox.Set(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));

    groundBody->CreateFixture(&groundBox, 0);

    

}

– (void)start

{

    timer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(tick:) userInfo:nil repeats:YES];

}

– (void)tick:(NSTimer*)sender

{

    int32 velocityIterations = 8;

    int32 positionIterations = 1;

    

    world->Step(1.0f/60.0f, velocityIterations, positionIterations);

    

    for (b2Body* b = world->GetBodyList(); b; b=b->GetNext()) {

        if (b->GetUserData() != NULL) {

            UIView *oneView = (__bridge UIView *)b->GetUserData();

CGPoint newCenter = CGPointMake(b->GetPosition().x * PTM_RATIO,

                                            self.view.bounds.size.height – b->GetPosition().y * PTM_RATIO);

oneView.center = newCenter;

            

CGAffineTransform transform = CGAffineTransformMakeRotation(- b->GetAngle());

            

oneView.transform = transform;

        }

    }

    

    if (ballThrow) {

        

        { // counter for ghost

            static int counter;

            counter++;

            if (counter > 5) {

                counter = 0;

                [self showGhost];

            }

        }

        

        self.view.center = CGPointMake(self.view.window.center.x, ball.center.x);

        if (!meter) {

            meter = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 200, 50)];

            meter.transform = self.view.transform;

            meter.font = [UIFont boldSystemFontOfSize:40];

            [self.view.window addSubview:meter];

            

            // reset button

            UILabel *reset = [[UILabel alloc] initWithFrame:CGRectMake(250, 50, 50, 50)];

            reset.transform = self.view.transform;

            reset.text = @”reset”;

            reset.userInteractionEnabled = YES;

            [self.view.window addSubview:reset];

            UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reset)];

            [reset addGestureRecognizer:tap];

        }

        meter.text = [NSString stringWithFormat:@”%.2f”, ball.center.x];

    }

}

– (void)showGhost

{    

    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];

    v.center = ball.center;

    v.transform = ball.transform;

    v.backgroundColor = ball.backgroundColor;

    v.layer.borderColor =[UIColor whiteColor].CGColor;

    v.layer.borderWidth = 1.0;

    v.alpha = 0.8;

    [self.view insertSubview:v belowSubview:ball];

    [UIView animateWithDuration:1.0 animations:^{

        v.alpha = 0.1;

    } completion:^(BOOL finished) {

        [v removeFromSuperview];

    }];

}

– (void)addPhysicalBodyForView:(UIView *)physicalView

{

    b2BodyDef bodyDef;

    bodyDef.type = b2_dynamicBody;

    

    CGPoint p = physicalView.center;

    CGPoint boxDimensions = CGPointMake(physicalView.bounds.size.width/PTM_RATIO/2.0, physicalView.bounds.size.height/PTM_RATIO/2.0);

    

    bodyDef.position.Set(p.x/PTM_RATIO, (460.0 – p.y)/PTM_RATIO);

    bodyDef.userData = (__bridge void *)physicalView;

    

    b2Body *body = world->CreateBody(&bodyDef);

    b2PolygonShape dynamicBox;

    dynamicBox.SetAsBox(boxDimensions.x, boxDimensions.y);

    

    b2FixtureDef fixtureDef;

    fixtureDef.shape = &dynamicBox;

    fixtureDef.density = 5.0f;

    fixtureDef.friction = 1.1f;

    fixtureDef.restitution = 0.1f;

    body->CreateFixture(&fixtureDef);

    

    body->SetType(b2_dynamicBody);

}

– (void)jointView:(UIView*)v

{

    b2DistanceJointDef jointDef;

    

    box = world->GetBodyList();

    b2BodyDef newBodyDef;

    newBodyDef.type = b2_dynamicBody;

    

    CGPoint boxDimensions = CGPointMake(v.bounds.size.width/PTM_RATIO/2.0, v.bounds.size.height/PTM_RATIO/2.0);

    

    CGPoint p = v.center;

    newBodyDef.position.Set(p.x/PTM_RATIO, (460.0 – p.y)/PTM_RATIO);

    newBodyDef.userData = (__bridge void *)v;

    b2Body* newBody = world->CreateBody(&newBodyDef);

    

    b2PolygonShape dynamicBox;

    dynamicBox.SetAsBox(boxDimensions.x, boxDimensions.y);

    b2FixtureDef fixtureDef;

    fixtureDef.shape = &dynamicBox;

    fixtureDef.density = 3.0f;

    fixtureDef.friction = 0.3f;

    fixtureDef.restitution = 0.5f;

    newBody->CreateFixture(&fixtureDef);

    

    jointDef.Initialize(box, newBody, box->GetPosition(), newBody->GetPosition());

    jointDef.collideConnected = true;

    jointDef.frequencyHz = 2.0f;

    jointDef.dampingRatio = 2.1;

    joint = world->CreateJoint(&jointDef);

}

– (void)pan:(UIGestureRecognizer*)gr

{

    if (gr.state == UIGestureRecognizerStateBegan) {

        box->SetType(b2_staticBody);

    }

    

    if (gr.state == UIGestureRecognizerStateEnded) {

        box->SetType(b2_dynamicBody);

        world->DestroyJoint(joint);

        ballThrow = 1;

        

        [gr.view removeGestureRecognizer:gr];

    }

    

    CGPoint p = [gr locationInView:self.view];

    gr.view.center = p;

    float32 angle = box->GetAngle();

    const b2Vec2 position(p.x/PTM_RATIO,(self.view.bounds.size.height – p.y)/PTM_RATIO);

    box->SetTransform(position, angle);

    if (!box->IsAwake()) {

//        box->SetAwake(true);

         for (b2Body* b = world->GetBodyList(); b; b=b->GetNext()) {

             b->SetAwake(true);

         }

    }

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end