Tutorial: Cocos2d und Physik

Hallo Zusammen,

heute behandeln wir eine weitere Stärke des Cocos2d Frameworks – die eingebaute Chipmunk Physik Engine. Durch diese Engine ist es möglich Objekte und eine physikalische Umgebung zu definieren. Anschließend verhalten sich diese Objekte physikalisch korrekt. Die Möglichkeiten sind dabei vielfältig: die Umgebung kann eine Gravitation haben oder nicht; Objekte sind schwer oder leicht; verhalten sich gummiartig oder doch eher steinhart.
In dem heutigen Tutorial lernen wir eine solche physikalisch korrekte Umgebung zu erstellen.

Leider haben die diversen Möglichkeiten den Nachteil unzähliger Parameter an denen man drehen kann. So muss zunächst die Umgebung erstellt werden. Wollen wir nun ein Objekt hinzufügen, bedarf es wieder vieler einzelschritte. Als erstes wird ein sogenannter cpBody erstellt. Diesem wird ein Gewicht zugeordnet, eventuell sogar eine Beschleunigung usw. Anschließend braucht der cpBody eine Form, so dass die Physikengine weiß, wenn es zu einer Kollision kommt. Also erstellen wir ein cpShape, um die Form des Objektes zu definieren (z.B. als Kreis). Anschließend kann dem ganzen optional noch eine Bild hinzugefügt werden und zu guter Letzt müssen die Einzelkomponenten verbunden werden.
Hier nur einmal ein Stück Beispielcode für die Erstellung eines Objektes:

   cpBody *ballBody = cpBodyNew(100.0, INFINITY);
   ballBody->p = cpv(160, 240);
   cpSpaceAddBody(space, ballBody);  
   cpShape *ballShape = cpCircleShapeNew(ballBody, 15.0, cpvzero);
   ballSprite = [CCSprite spriteWithFile:@"ballSprite.png"];
   ballShape->data = ballSprite;
   cpSpaceAddShape(space, ballShape);

Ziemlich kompliziert, dabei sind noch gar keine besonderen Parameter enthalten. Zum Glück gibt es auch hierfür Abhilfe: den Chipmunk-Spacemanger

Um zu zeigen was der Spacemanager alles kann, erstellen wir ein neues Projekt in XCode. Es muss nun der Ordner src aus dem Download eurem Projekt hinzugefügt werden. Falls ihr ARC nutzt, was ihr tun solltet, denkt daran auch die Spacemanager Klassen mit –fno-objc-arc zu kennzeichnen.

Aus dem HelloWorldLayer.h und HelloWorldLayer.m  schmeißen wir alles raus, außer die scene, init und touch Methoden.  Anschließend ergänzen wir unseren Spacemanager in HelloWorldLayer.h

#import "SpaceManagerCocos2d.h"

@interface Game : CCLayer{
      //Spacemanager
      SpaceManagerCocos2d *smgr;
}

Und in HelloWorld.m

if ((self = [super init])) {
        //allocate our space manager
        smgr = [[SpaceManagerCocos2d alloc] init];
}

Nun erzeugen wir den Ball von oben erneut – diesmal aber etwas einfacher.

 if ((self = [super init])) {
          //allocate our space manager
         smgr = [[SpaceManagerCocos2d alloc] init];

        [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:NO];

        cpShape *shape = [smgr addCircleAt: ccp(200, 300) mass:100 radius:8];
        cpCCSprite  *ball = [[cpCCSprite alloc] initWithFile:@"ball.png"];
        ball.shape = shape;
        [self addChild:ball];
        [smgr start];
}

Wir drücken auf Play und schauen was passiert.
Der Ball wird erzeugt…
..und fällt unten aus dem Bild. Wie enttäuschend. Aber auch logisch – wir haben ja noch keine Begrenzung der Welt definiert. Das sollten wir nun nachholen.

-(void)createWorldBoundries{
        CGSize s = [[CCDirector sharedDirector] winSize];

       // bottom
      [smgr addSegmentAtWorldAnchor:cpv(0,0) toWorldAnchor:cpv(s.width ,0) mass:STATIC_MASS radius:1];

      // top
      [smgr addSegmentAtWorldAnchor:cpv(s.width,s.height) toWorldAnchor:cpv(0,s.height) mass:STATIC_MASS radius:1];

      // left
      [smgr addSegmentAtWorldAnchor:cpv(0,s.height) toWorldAnchor:cpv(0,0) mass:STATIC_MASS radius:1];

      // right
      [smgr addSegmentAtWorldAnchor:cpv(s.width,0) toWorldAnchor:cpv(s.width,s.height) mass:STATIC_MASS radius:1];
}

Das sieht schon besser aus :-)
Aber wir brauchen mehr Bälle und vielleicht ein paar Hindernisse. Erzeugen wir zunächst die Hindernisse:

-(void) createObstacles{
         cpShape *shape = [smgr addRectAt:ccp(120,70) mass:STATIC_MASS width:100 height:25 rotation:40];
         cpShapeNode *node = [cpShapeNode nodeWithShape:shape];
         node.color = ccRED;
         [self addChild:node]; 

         cpShape *shape2 = [smgr addRectAt:ccp(220,190) mass:STATIC_MASS width:100 height:25 rotation:-40];
         cpShapeNode *node2 = [cpShapeNode nodeWithShape:shape2];
         node2.color = ccRED;
         [self addChild:node2];
}

Vergesst nicht die Methoden auch in init aufzurufen.


Als letzten Schritt sollten wir das gnaze noch ein wenig interaktiver gestalten. Hierzu nehmen  wir den Code zum Erstellen der Bälle aus der init heraus und kopieren ihn in die Touchbegan Mehtode. Gleichzeitig ändern wir den Punkt an dem der Ball erzeugt wird auf den Punkt des Touches.

- (BOOL)ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event
{
    CGPoint pt = [self convertTouchToNodeSpace:touch];
    cpShape *shape = [smgr addCircleAt:pt mass:100 radius:8];
    cpCCSprite  *ball = [[cpCCSprite alloc] initWithFile:@"ball.png"];
    ball.shape = shape;
    [self addChild:ball];

	return YES;
}

Von hier an ist es nicht mehr weit bis zu einem netten kleinen Physik-Puzzelspiel.
Aber dazu beim nächsten Mal mehr.
Viel Spaß beim rumprobieren.

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.