ダンプトラックに積んだ砂をザザーッとおろすサンプル

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

概要

画面をタッチすると、ダンプカーの荷台が傾くように作ってみました。

一回目のタッチで、土砂をおろす。

二回目のタッチで、荷台を戻して、土砂を補給

これを繰り返して、砂山を作っていく感じです。

ポイント

Box2dを使います。

今回は、b2RevoluteJointを使うことで、

荷台の上げ下げを制御しています。


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.0

@interface ViewController () {

    b2World *world;

    NSTimer *timer;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    

    [self createWorld];

    

    [self start];

    

    [self createTrack];

    

    [self createGravel];

}

– (void)createWorld

{

    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/PTM_RATIO, 0));

    groundBody->CreateFixture(&groundBox, 0);

    

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

    groundBody->CreateFixture(&groundBox, 0);

    

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

    groundBody->CreateFixture(&groundBox, 0);

}

– (void)createTrack

{

    // truck view

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

    v.center = CGPointMake(220, 430);

    v.backgroundColor = [UIColor clearColor];

    [self.view addSubview:v];

    b2FixtureDef fixtureDef;

fixtureDef.density = 3.0f;

fixtureDef.friction = 0.3f;

fixtureDef.restitution = 0.5f;

    b2Body *bodyA = [self addPhysicalBodyForView:v type:fixtureDef];

    

    // truck body

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

    truckBody.backgroundColor = [UIColor yellowColor];

    [v addSubview:truckBody];

    

    // truck front

    UIView *truckFront = [[UIView alloc] initWithFrame:CGRectMake(250, 365, 40, 60)];

    truckFront.backgroundColor = [UIColor redColor];

    [self.view addSubview:truckFront];

    b2Body *front = [self addPhysicalBodyForView:truckFront type:fixtureDef];

    

    

    UIView *frontWindow = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 25, 30)];

    frontWindow.backgroundColor = [UIColor blueColor];

    [truckFront addSubview:frontWindow];

    b2RevoluteJointDef jointDef0;

    jointDef0.Initialize(bodyA, front, b2Vec2(270.0/PTM_RATIO, 40.0/PTM_RATIO));

    jointDef0.lowerAngle = 0;

    jointDef0.upperAngle = 0;

    jointDef0.enableLimit = true;

    world->CreateJoint(&jointDef0);

    

    

    // truck tires

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

    truckTireA.backgroundColor = [UIColor blackColor];

    truckTireA.layer.cornerRadius = 15.0;

    truckTireA.center = CGPointMake(20, 45);

    [v addSubview:truckTireA];

    

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

    truckTireB.backgroundColor = [UIColor blackColor];

    truckTireB.layer.cornerRadius = 15.0;

    truckTireB.center = CGPointMake(120, 45);

    [v addSubview:truckTireB];

    

    

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

    v2.center = CGPointMake(200, 410);

    v2.backgroundColor = [UIColor blackColor];

    [self.view addSubview:v2];

fixtureDef.density = 3.0f;

fixtureDef.friction = 0.3f;

fixtureDef.restitution = 0.5f;

    b2Body *bodyB = [self addPhysicalBodyForView:v2 type:fixtureDef];

    

    b2RevoluteJointDef jointDef;

    b2Vec2 center = b2Vec2(160.0/PTM_RATIO, 25.0/PTM_RATIO);

    jointDef.Initialize(bodyA, bodyB, center);

    jointDef.lowerAngle = 0;

    // -90 degrees

    jointDef.upperAngle = 0.25f * b2_pi;

    // 45 degrees

    jointDef.enableLimit = true;

    jointDef.maxMotorTorque = 20000.0f;

    jointDef.motorSpeed = 0.0f;

    jointDef.enableMotor = true;

    

    world->CreateJoint(&jointDef);

}

– (void)createGravel

{

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

        int x = arc4random() % 20 + 170;

        

        UIView *v = [[UIView alloc] initWithFrame:CGRectMake(x, 350, 5, 5)];

        v.tag = 10;

        v.backgroundColor = [UIColor brownColor];

        [self.view addSubview:v];

        

        b2FixtureDef fixtureDef;

        fixtureDef.density = 30.0f;

        fixtureDef.friction = 1000.0f;

        fixtureDef.restitution = 0.0f;

        [self addPhysicalBodyForView:v type:fixtureDef];

    }

}

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

{

    static float speed;

    if (speed > 0) {

        speed = –1.0f;

        [self performSelector:@selector(createGravel) withObject:nil afterDelay:3.0];

    } else {

        speed = 1.0f;

    }

    

    b2RevoluteJoint *j = (b2RevoluteJoint *)world->GetJointList();

    j->SetMotorSpeed(speed);

}

-(b2Body*)addPhysicalBodyForView:(UIView *)physicalView type:(b2FixtureDef)fixtureDef

{

// Define the dynamic body.

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;

    

// Tell the physics world to create the body

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

    

// Define another box shape for our dynamic body.

b2PolygonShape dynamicBox;

    

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

    fixtureDef.shape = &dynamicBox;

body->CreateFixture(&fixtureDef);

    

// a dynamic body reacts to forces right away

body->SetType(b2_dynamicBody);

    

    return body;

}

– (void)start

{

    // タイマーをスタート

timer = [NSTimer scheduledTimerWithTimeInterval:1.0f/60.0f 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;

}

}

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end