Box2dを使ってプルプルするタイヤみたいなものを作ってみる

(XcodeのiOS6 iPhone Simulatorで作っています。)

ポイント

・b2DistanceJointDefで物体を繋ぎ合わせる

・真ん中にハブをおいて、周りに丸を並べることで、タイヤっぽく

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 PTMRatio 16

@interface ViewController () {

    b2World *world;

    NSTimer *timer;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    

    [self createPhysicsWorld];

    

    [self start];

}

– (void)createPhysicsWorld

{

    CGSize screenSize = self.view.bounds.size;

    

    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, 0), b2Vec2(screenSize.width/PTMRatio, 0));

    groundBody->CreateFixture(&groundBox, 0);

    

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

    groundBody->CreateFixture(&groundBox, 0);

    

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

    groundBody->CreateFixture(&groundBox, 0);

}

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    [self addSoftCircles];

}

– (void)start

{

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

}

– (void)tick:(NSTimer*)sender

{

    int32 velocityIteration = 8;

    int32 positionIteration = 1;

    

    world->Step(1.0f/60.0f, velocityIteration, positionIteration);

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

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

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

            CGPoint newCenter = CGPointMake(b->GetPosition().x * PTMRatio, self.view.bounds.size.height – b->GetPosition().y * PTMRatio);

            v.center = newCenter;

        }

    }

}

– (void)addSoftCircles

{

    b2Body** parts = (b2Body**)b2Alloc(sizeof(b2Body*) * 12);

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

        float th = i * M_PI/6.0 + M_PI * 0.1;

        float x = 50 * cos(th) + 160;

        float y = 50 * sin(th) + 160;

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

        ball.center = CGPointMake(x,y);

        ball.layer.cornerRadius = ball.bounds.size.width / 2.0;

        ball.backgroundColor = [UIColor blueColor];

        ball.alpha = 0.2;

        ball.layer.borderWidth = 2.0;

        [self.view addSubview:ball];

        

        // Create ball body

        b2BodyDef ballBodyDef;

        ballBodyDef.type = b2_dynamicBody;

        CGPoint p = ball.center;

        ballBodyDef.position.Set(p.x/PTMRatio, (460.0 – p.y)/PTMRatio);

        ballBodyDef.userData = (__bridge void *)ball;

        parts[i] = world->CreateBody(&ballBodyDef);

        

        // Create circle shape

        b2CircleShape circle;

        circle.m_radius = ball.bounds.size.width/2.0/PTMRatio;

        

        // Create shape definition and add to body

        b2FixtureDef ballShapeDef;

        ballShapeDef.shape = &circle;

        ballShapeDef.density = 1.0f;

        ballShapeDef.friction = 0.0f;

        ballShapeDef.restitution = 0.5f;

        

        parts[i]->CreateFixture(&ballShapeDef);

    }

    

    UIView *hub = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];

    hub.center = CGPointMake(160, 160);

    hub.layer.cornerRadius = hub.bounds.size.width / 2.0;

    hub.backgroundColor = [UIColor blueColor];

    hub.alpha = 0.2;

    hub.layer.borderWidth = 2.0;

    [self.view addSubview:hub];

    

    // Create ball body

    b2BodyDef hubBodyDef;

    hubBodyDef.type = b2_dynamicBody;

    CGPoint p = hub.center;

    hubBodyDef.position.Set(p.x/PTMRatio, (460.0 – p.y)/PTMRatio);

    hubBodyDef.userData = (__bridge void *)hub;

    b2Body* hubBody = world->CreateBody(&hubBodyDef);

    

    // Create circle shape

    b2CircleShape circle;

    circle.m_radius = hub.bounds.size.width/2.0/PTMRatio;

    

    // Create shape definition and add to body

    b2FixtureDef hubShapeDef;

    hubShapeDef.shape = &circle;

    hubShapeDef.density = 1.0f;

    hubShapeDef.friction = 0.0f;

    hubShapeDef.restitution = 0.5f;

    hubBody->CreateFixture(&hubShapeDef);

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

        // 隣と繋ぐ

        b2DistanceJointDef jointDef;

        jointDef.Initialize(parts[i], parts[(i+1) % 6], parts[i]->GetPosition(), parts[(i+1)%6]->GetPosition());

        jointDef.collideConnected = true;

        jointDef.frequencyHz = 40.0f;

        jointDef.dampingRatio = 0.5;

        world->CreateJoint(&jointDef);

        

        // 中央と繋ぐ

        jointDef.Initialize(parts[i], hubBody, parts[i]->GetPosition(), hubBody->GetPosition());

        jointDef.collideConnected = true;

        jointDef.frequencyHz = 10.0f;

        jointDef.dampingRatio = 0.5;

        world->CreateJoint(&jointDef);

    }

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end