ダンプトラックに積んだ砂をザザーッとおろすサンプル
(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