【Xcode5】Xcodeの使い方 SpriteKit 編 Vol13 〜 スクロールについての考察 cameraとセンタリングについて〜


gifが重すぎ。。。

以前記述したスクロールからの続き(【Xcode5】Xcodeの使い方 SpriteKit 編 Vol8 〜 スクロールについての考察〜 - @kitano_ow 's blog)

以下の公式のドキュメントを元に、
センタリングを用い画面をスクロールするような動きを実現してみたいと思います。
Sprite Kit Programming Guide: Advanced Scene Processing

※こちらはスクロールというより、あるノード(例えばキャラクターなど)の動きに合わせて、
センタリングさせるという考え方になるかと思います。

この場合は、worldとcameraという考え方を用いています。

1.world と cameraの配置

worldがゲームの全体とすると、
cameraは中央表示を行うための管理ノードというイメージかなと考えてます。※間違ってたらすみません。

今回も横画面として(参照)

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        
        self.anchorPoint = CGPointMake(0.5f, 0.5f);
        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];

        SKSpriteNode *background = [SKSpriteNode spriteNodeWithImageNamed:@"gra.png"];
        [myWorld addChild:background];
        
        SKSpriteNode *myWorld = [[SKSpriteNode alloc] initWithImageNamed:@"longback.png"];
        myWorld.name = @"world";
        [self addChild:myWorld];
        
        SKNode *camera = [SKNode node];
        camera.name = @"camera";
        [myWorld addChild:camera];
        
    }
    return self;
}

としています。

gra.pngは背景用のグラデーションの画像です。
またシーンのanchorPointを0.5,0.5としています。
基本的には先ほどの公式ドキュメントに合わせての実装になっています。

2.表示シーンの中央表示

- (void)didSimulatePhysics
{
    //nameより、cameraノードを取得
    SKNode *camera = [self childNodeWithName: @"//camera"];
    [self centerOnNode: camera];
}

- (void) centerOnNode: (SKNode *) node
{
    CGPoint cameraPositionInScene = [node.scene convertPoint:node.position fromNode:node.parent];
    node.parent.position = CGPointMake(node.parent.position.x - cameraPositionInScene.x,                                       node.parent.position.y - cameraPositionInScene.y);
}

centerOnNodeは引数nodeのpositionが現在アプリとして表示させている領域の中央になるように、
node.parent( = world)のpositionが変更されるような形になっています。

didSimulatePhysicsはSKSceneのメソッドで、
物理シュミレーションが実行された後に毎回実行されるもので
ノードの物理動作(なんか微妙な表現。。)毎に処理を差し込みたい場合など有効です。

公式のドキュメントとしては以上ですが、
あるノードを追跡するようにしシーンの切り替えをしてみたいと思います。

地面(ground)とボール(circle)を起き、タップしたらそのボールが跳ねるような
動きを実現してみます。

まず、インスタンス変数を今回利用するインスタンス変数を追加

@implementation MyScene
{
    SKSpriteNode *circle;
    int isAction;
}

initWithSizeに以下を追記。

        //地面
        SKSpriteNode *ground = [[SKSpriteNode alloc] initWithColor:[SKColor greenColor]
                                                              size:CGSizeMake(size.width*2, size.height*2)];
        ground.position = CGPointMake(0, -ground.size.height/2);
        ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
        ground.physicsBody.dynamic = NO;
        [myWorld addChild:ground];
        
        
        //ボール
        circle = [SKSpriteNode spriteNodeWithImageNamed:@"circle.png"];
        circle.position = CGPointMake(0, circle.size.height/2);
        [myWorld addChild:circle];
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */
    circle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:circle.size];
    circle.physicsBody.dynamic = YES;
    [circle.physicsBody applyForce:CGVectorMake(100, 500)];
    //bool。押されたどうかフラグ
    isAction = true;
}

ただこれだけでは、ボールが跳ねますが、背景などは変わりません。

そこで、cameraの中心が現在表示される領域の中心になるようになっているため、
circleの中心をcameraの中心にすると、circleを追跡するような動きが実現できるかと思います。

- (void)didSimulatePhysics
{
    SKNode *camera = [self childNodeWithName: @"//camera"];
    if(isAction) {
        camera.position = circle.position;
        if(circle.position.y < 0) {
            circle.physicsBody.dynamic = NO;
        }
    }
    [self centerOnNode: camera];
}


そうすることで

このような動きになります。