概要

五角形等のポリゴンをBox2dを使って表示してみる。

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

ポイント

・PanGestureRecognizerをつかって指で移動させる

・PolygonShapeのSet(points, 5) で五角形

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 <Box2D/Box2D.h>

#import “ViewController.h”

//

// PolygonMesh

//

@interface PolygonMesh : UIView

@property (nonatomic, assign) CGPoint p1,p2,p3,p4,p5;

@end

@implementation PolygonMesh

@synthesize p1,p2,p3,p4,p5;

– (id)initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    if (self) {

        self.backgroundColor = [UIColor clearColor];

    }

    return self;

}

-(void)drawRect:(CGRect)rect

{

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    [[UIColor redColor] set];

    CGContextSetLineWidth(ctx, 2.0);

    

    NSArray *arr = [NSArray arrayWithObjects:[NSValue valueWithCGPoint:p1],[NSValue valueWithCGPoint:p2],[NSValue valueWithCGPoint:p3],[NSValue valueWithCGPoint:p4],[NSValue valueWithCGPoint:p5], nil];

    

    for (int i=1; i<[arr count] + 1; i++) {

        CGPoint start = [[arr objectAtIndex:i-1] CGPointValue];

        CGPoint end = [[arr objectAtIndex:i % ([arr count])] CGPointValue];

        if (!CGPointEqualToPoint(end,CGPointZero)) {

            CGContextMoveToPoint(ctx, start.x, start.y);

            CGContextAddLineToPoint(ctx, end.x, end.y);

            CGContextStrokePath(ctx);

            CGContextFillEllipseInRect(ctx, CGRectMake(end.x4, end.y4, 8, 8));

        }

    }

}

@end

//

// ViewController

//

#define PTM_RATIO 16.0

@interface ViewController () {

    b2World *world;

    NSTimer *timer;

    int status;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    self.view.backgroundColor = [UIColor blackColor];

    [super viewDidLoad];

    [self createWorld];

    [self createPolygons];

    [self start];

}

-(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); // bottom-left corner

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)createPolygons

{

    // Viewを用意

    float r = 45;

    float angle = M_PI / 2.5;

    PolygonMesh *pentagon = [[PolygonMesh alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];

    pentagon.p1 = CGPointMake(r*cos(angle)+50, r*sin(angle)+50);

    pentagon.p2 = CGPointMake(r*cos(angle*2)+50, r*sin(angle*2)+50);

    pentagon.p3 = CGPointMake(r*cos(angle*3)+50, r*sin(angle*3)+50);

    pentagon.p4 = CGPointMake(r*cos(angle*4)+50, r*sin(angle*4)+50);

    pentagon.p5 = CGPointMake(r*cos(angle*5)+50, r*sin(angle*5)+50);

    [self.view addSubview:pentagon];

    

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

    [pentagon addGestureRecognizer:pan];

    

    // Box2dViewを連携

    b2BodyDef bodyDef;

    bodyDef.type = b2_dynamicBody;

    CGPoint p = pentagon.center;

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

    bodyDef.userData = (__bridge void *)pentagon;

    

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

    

    b2Vec2 points[5];

    float x,y;

    

    CGPoint wp;

    wp = pentagon.p1;

    x = (wp.x – pentagon.center.x) / PTM_RATIO;

    y = (pentagon.center.y – wp.y) / PTM_RATIO;

    points[0].Set(x, y);

    

    wp = pentagon.p2;

    x = (wp.x – pentagon.center.x) / PTM_RATIO;

    y = (pentagon.center.y – wp.y) / PTM_RATIO;

    points[1].Set(x,y);

    

    wp = pentagon.p3;

    x = (wp.x – pentagon.center.x) / PTM_RATIO;

    y = (pentagon.center.y – wp.y) / PTM_RATIO;

    points[2].Set(x, y);

    

    wp = pentagon.p4;

    x = (wp.x – pentagon.center.x) / PTM_RATIO;

    y = (pentagon.center.y – wp.y) / PTM_RATIO;

    points[3].Set(x, y);

    

    wp = pentagon.p5;

    x = (wp.x – pentagon.center.x) / PTM_RATIO;

    y = (pentagon.center.y – wp.y) / PTM_RATIO;

    points[4].Set(x, y);

    

    b2PolygonShape dynamicBox;

    dynamicBox.Set(points, 5);

    

    b2FixtureDef fixtureDef;

    fixtureDef.shape = &dynamicBox;

    fixtureDef.density = 1.0f;

    fixtureDef.friction = 0.3f;

    fixtureDef.restitution = 0.5f;

    body->CreateFixture(&fixtureDef);

    

    body->SetType(b2_dynamicBody);

}

– (void)tap:(UIGestureRecognizer*)gr

{

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

    if (gr.state == UIGestureRecognizerStateBegan) {

        status = 1;

    } else if (gr.state == UIGestureRecognizerStateChanged) {

        gr.view.center = p;

    } else if (gr.state == UIGestureRecognizerStateEnded){

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

            if ((__bridge UIView *)b->GetUserData() == gr.view) {

                float32 angle = b->GetAngle();

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

                b->SetTransform(position, angle);

                b->SetType(b2_dynamicBody);

                

                if (!b->IsAwake()) {

                    b->SetAwake(true);

                }

            }

        }

        status = 0;

    }

}

– (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 = 2;

    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();

            if (status == 0) {

                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