[ cocos2d-html ] ブロック崩し -ボールを動かす!

前回に引き続き、ブロック崩しの作成について、説明していきます。
ボールの移動処理についてです。

ブロック崩しのボールアクションにはいくつか種類があります。
「ボールの発射」「壁やブロックにぶつかった場合の跳ね返り」等です。

これらをすべてをcocos2dのアクションで行うのは、あまり効率的とは言えません。
プログラムには、無料で使用することの出来るライブラリが多々あります。
今回はその中の一つである、Box2dというライブラリを使用してアクションを行っていきたいと思います。

Box2dというのはゲーム用の「2D物理エンジン」で、cocos2d-htmlに標準で入っています。
詳しくはWikipediaをご覧ください。

使用するために、下記ファイルの一部を修正します。
Cocos2d-html5-v2.2.1
┗HelloHTML5World
cocos2d.js

  1. //変更前
  2. box2d:false,
  3. //変更後
  4. box2d:true,

これでBox2dを使用するために準備が終わりました。
それではさっそく、Box2dを使用したコーディングに入りましょう!

Box2Dのベースを作成します。
グローバル変数に以下を追加します。

  1. //1Mあたりのpx値
  2. var PTM_RATIO = 32;
  3. //cocos2d-xのlayer
  4. var layer = null;
  5. //box2d の world
  6. var world = null;
  7. //box2d関連
  8. var b2BodyDef = Box2D.Dynamics.b2BodyDef;
  9. var b2Body = Box2D.Dynamics.b2Body;
  10. var b2FixtureDef = Box2D.Dynamics.b2FixtureDef;
  11. var b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape;
  12. var b2Vec2 = Box2D.Common.Math.b2Vec2;
  13. var b2World = Box2D.Dynamics.b2World;
  14. //弾の速度
  15. var ball_velocity = 8;
  16. //弾の角度
  17. var ball_angle = 60.0 / 180;
  18. //弾の速度(時速 5M)
  19. var BALL_VELOCITY = 5;
  20. //弾のbody
  21. var body_ball = null;
  22. //バーのbody
  23. var body_bar = null;
  24. //ブロックのbody
  25. var body_block = new Array();

PTM_RATIOとは、コメントでも書いてありますが
1メートルあたりのピクセル値です。
なんでメートル?と思われる方もいると思いますがこれは
cocos2dでは座標やアクション移動量等の長さの単位にピクセルを使用しているのに対して
box2dではメートルを使用しています。
その為、1メートルあたりのピクセル値を設定してあげる必要があるのです。

次に、b2World(box2dでの物理世界)の生成を行います。
init内に以下を追加します。

  1. //box2d world生成
  2. world = new b2World(new b2Vec2(0, 0), true);
  3. world.SetContinuousPhysics(true);

以下の関数も追加しましょう。

  1. addNewSpriteWithCoords:function (sprite, p, width, height, dynamic) {
  2.   var bodyDef = new b2BodyDef();
  3.   if (dynamic == true) {
  4.     bodyDef.type = b2Body.b2_dynamicBody;
  5.     bodyDef.position.Set(1.0 * p.x / PTM_RATIO, 1.0 * p.y / PTM_RATIO);
  6.     bodyDef.userData = sprite;
  7.   } else {
  8.     bodyDef.type = b2Body.b2_staticBody;
  9.     bodyDef.position.Set(1.0 * p.x / PTM_RATIO, 1.0 * p.y / PTM_RATIO);
  10.     bodyDef.userData = sprite;
  11.   }
  12.   var body = world.CreateBody(bodyDef);
  13.   var dynamicBox = new b2PolygonShape();
  14.   dynamicBox.SetAsBox(1.0 * width / PTM_RATIO / 2.0, 1.0 * height / PTM_RATIO / 2.0);
  15.   //Define the dynamic body fixture.
  16.   var fixtureDef = new b2FixtureDef();
  17.   fixtureDef.shape = dynamicBox;
  18.   //密度
  19.   fixtureDef.density = 1.0;
  20.   //摩擦係数
  21.   fixtureDef.friction = 0;
  22.   //反発係数
  23.   fixtureDef.restitution = 1;
  24.   //設定する
  25.   body.CreateFixture(fixtureDef);
  26.   return body;
  27. },
  28. update:function (dt) {
  29.   var velocityIterations = 8;
  30.   var positionIterations = 1;
  31.   world.Step(dt, velocityIterations, positionIterations);
  32.   for (var b = world.GetBodyList(); b; b = b.GetNext()) {
  33.     if (b.GetUserData() != null) {
  34.       var myActor = b.GetUserData();
  35.       myActor.setPosition(cc.p(b.GetPosition().x * PTM_RATIO, b.GetPosition().y * PTM_RATIO));
  36.       myActor.setRotation(-1 * cc.RADIANS_TO_DEGREES(b.GetAngle()));
  37.     }
  38.   }
  39. },

addNewSpriteWithCoordsは、Spriteにbox2dを使用する上で必要な要素を設定している関数です。
引数で、”Spriteのオブジェクト”、”CCpoint(座標)”、”Spriteの幅”、”Spriteの高さ”、”dynamicの真偽”を受け取っています。
初めのif文で、動的か静的かの判定を行っており
dynamicがtrueの場合は動的(DynamicBody)、falseの場合は静的(StaticBody)になります。
SetAsBoxでボックスシェイプを生成し、その後に摩擦係数や反発係数などを設定した上で物理オブジェクトを返しています。
※シェイプについてはこちらをご覧ください。

updateは、フレーム毎に呼ばれるメソッドで
このメソッドによって物体の座標変更(移動)や回転を行っています。

上記関数を使用して、配置済みのバーとブロックに物理オブジェクトを生成します。

  1. //バーのSprite生成部に追加
  2. body_bar = this.addNewSpriteWithCoords(spr_bar, cc.p( size.width / 2 – 5, BAR_Y ), BAR_WIDTH, BAR_HEIGHT, false);
  3. //ブロックのSprite生成部に追加
  4. body_block[i * 8 + j] = this.addNewSpriteWithCoords(spr_block[i * 8 + j], cc.p( 20 + ( j * 40 ), 370 – h_size), BLOCK_WIDTH, BLOCK_HEIGHT, false);

updateメソッドを呼ぶ処理も忘れずに記載。
this.scheduleUpdate();

先ほど生成したバーの物理オブジェクトを、バーSpriteと同時に動かすためにMove関数内に以下を追加します。
body_bar.SetPosition(cc.p(spr_bar.getPositionX() / PTM_RATIO, spr_bar.getPositionY() / PTM_RATIO));

最後に、バー上に存在する弾を発射するための処理を
TouchesEndedメソッド内に追記します。

  1. var size = cc.Director.getInstance().getWinSize();
  2. body_ball = this.addNewSpriteWithCoords(spr_ball, cc.p( size.width / 2 – 5, BAR_Y + BAR_HEIGHT / 2 + BALL_HEIGHT / 2 ), BALL_WIDTH, BALL_HEIGHT, true);
  3. var b2Vec2 = Box2D.Common.Math.b2Vec2;
  4. var ball_angle_work = Math.random() * 40;
  5. if (ball_angle_work < 20) {
  6.   ball_angle_work = -1 * ball_angle_work – 20;
  7. } else {
  8.   ball_angle_work = ball_angle_work;
  9. }
  10. ball_angle = ball_angle_work / 180;
  11. body_ball.SetLinearVelocity(new b2Vec2(-1 * ball_velocity * Math.sin(ball_angle), ball_velocity * Math.cos(ball_angle)));

これで弾の発射と、ブロック及びバーに衝突した時の跳ね返る動作が可能になります。
まだまだ、左右の壁の反発設定やブロックが消える処理など
残っているものはたくさんありますが、大体の形は見えてきました。
box2dという物理エンジンを使用する以上、今までより内容が少し難しいですが
頑張って作成していきましょう。

以上で、本記事は終了となります。

今回の処理を追記したソースコードはこちら

<次回以降の更新について>
次回は、左右の壁やブロック等、box2dの実装について引き続き説明していきます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*