Flashで物理演算を使ったミニゲーム その1「Box2Dについて」
Flashで物理演算を使ったミニゲーム その2「WorldとBodyとジョイント」
Flashで物理演算を使ったミニゲーム その3「動かないBody」
Flashで物理演算を使ったミニゲーム その4「カウントダウンするタイマーと動くBody」
Flashで物理演算を使ったミニゲーム その5「動かないBodyに衝突した時の処理」
Flashで物理演算を使ったミニゲーム その6「動くBodyに衝突した時の処理」
Flashで物理演算を使ったミニゲーム その7「効果音・BGM・背景」
Flashで物理演算を使ったミニゲーム その8「lemonovelで使う」
前々々回Worldと作成し、Bodyを1つ作り
前々回動かないBodyを作り、
前回タイマーに合わせて出現する動くBodyを作りました。
今回は衝突時の処理を付けたいと思います。
ボスのHPになるパラメータを作り、
衝突した際、衝突したものがボスであったら攻撃しボスのHPを減らします。
またぶつかった時に斬撃があった風にしたいので
Tweenerを使って表現したいと思います。
Tweenerは色々なイメージングが使えるのでエフェクトに使うと可愛いです。
http://code.google.com/p/tweener/
こちらから言語に合わせたzipをダウンロードして解凍すると
「caurina」というフォルダが出来ますのでflaファイルと同じ階層に配置しました。
フォルダ内には斬撃用の画像と衝突時の処理用のasを追加しました。
まとめると
「Box2D」フォルダ
「caurina」フォルダ
game05.fla
game05.as
Zangeki.png
ContactListener.as
こんな感じ。
ステージ側は画像にて残り時間とボスのHPを配置
残り時間はクラス名disp_txt
ボスのHPはクラス名lp_txt
import caurina.transitions.Tweener;
Tweenerを使うためにインポート。
// 斬撃の画像 [Embed(source='Zangeki.png')] private static const ZanImage:Class;
斬撃の画像の読み込み。
// コンタクトリスナ var contactListener:ContactListener = new ContactListener(); contactListener.parent = this; m_world.SetContactListener(contactListener);
ワールド作成時にコンタクトリスナ追加。
// 衝突したシェイプ var s1:b2Shape = point.shape1; var s2:b2Shape = point.shape2; // 衝突したボディ var b1:b2Body = s1.m_body; var b2:b2Body = s2.m_body; if (b1.m_userData && b2.m_userData) { // ボスと衝突した if ((b1.m_userData.id == "id_my" && b2.m_userData.id == "id_boss") || (b2.m_userData.id == "id_my" && b1.m_userData.id == "id_boss")) { // 斬撃の画像のサイズと位置のセットアップ var zanImage:Bitmap = new ZanImage(); zanImage.width = 50; zanImage.height = 50; zanImage.x = -zanImage.width / 2; zanImage.y = -zanImage.height / 2; var spritez:Sprite = new Sprite(); spritez.x = point.position.x * DRAW_SCALE; spritez.y = point.position.y * DRAW_SCALE; spritez.addChild(zanImage); addChild(spritez); var anglez:Number = Math.random() * 360; var lengthz:Number = Math.random() * 100 + 50; var dxz:Number = spritez.x + lengthz * Math.cos(anglez); var dyz:Number = spritez.y + lengthz * Math.sin(anglez); // Tweenerで斬撃を飛ばす Tweener.addTween(spritez, { time: 3, scaleX: 0, scaleY: 0, alpha: 0, rotation: 600, x: dxz, y: dyz, onComplete: function():void { removeChild(spritez); } }); var i:int = int(lp_txt.text); i = i-20; lp_txt.text = String(i); } }
衝突時の処理。
ここで要約、idを付与したのが生きてきます。
「id_my」と「id_boss」が衝突した場合のみエフェクトを出し
更にHPのために用意したtxt「lp_txt.text」の数字を減らします。
◆ポップアップでサンプルswfを開く
(ボス・仲間・敵・斬撃画像:MGS技研)
ボスに衝突すると斬撃のエフェクトがTweenerにより表現され、
衝突するとボスのHPが減るようになりました。
◆ContactListenerの書き方参考にさせて頂きました。
「Box2DでActionScript物理プログラミング」の要点を箇条書き
◆サンプルソース全文
game05.as
package{ ////////////////////////////////////////////////////////////////////////////// // インポート ////////////////////////////////////////////////////////////////////////////// import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Bitmap; import flash.events.Event; import Box2D.Common.Math.*; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; import Box2D.Dynamics.Joints.b2Joint; import Box2D.Dynamics.Joints.b2MouseJoint; import Box2D.Dynamics.Joints.b2MouseJointDef; import Box2D.Dynamics.Joints.b2RevoluteJoint; import Box2D.Dynamics.Joints.b2RevoluteJointDef; import caurina.transitions.Tweener; import flash.events.MouseEvent; import flash.utils.Timer; import flash.events.TimerEvent; import flash.text.*; public class game05 extends Sprite{ //定数定義 private static const DRAW_SCALE:Number = 30; // ジョイントの定義 private var mouseJointDef:b2MouseJointDef; private var mouseJoint:b2MouseJoint; // 値セット用 private var centerX:Number; private var centerY:Number; // 斬撃の画像 [Embed(source='Zangeki.png')] private static const ZanImage:Class; public function game05(){ createWorld(); createMy(); createBoss(); createEnemy1(); addEventListener(Event.ENTER_FRAME, Update, false, 0, true); var timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER,onTimer); timer.start(); } ////////////////////////////////////////////////////////////////////////////// // ワールドの作成 ////////////////////////////////////////////////////////////////////////////// private function createWorld():void{ //物理エンジンのセットアップ var worldAABB:b2AABB = new b2AABB(); worldAABB.lowerBound.Set(-100,-100); worldAABB.upperBound.Set(100,100); //重力のセットアップ var gravity:b2Vec2 = new b2Vec2(0.0, 0.4); //範囲・重力・スリープの有無 var doSleep:Boolean = true; // ワールド内のセットアップ m_world = new b2World(worldAABB, gravity, true); // ワールド内座標の設定 centerX = stage.stageWidth / 2 / DRAW_SCALE; centerY = stage.stageHeight / 2 / DRAW_SCALE; // 上 var bodyTop:b2BodyDef = new b2BodyDef(); bodyTop.position.Set(centerX, 0); var topShapeDef:b2PolygonDef = new b2PolygonDef(); topShapeDef.SetAsBox(centerX, 0.2); topShapeDef.density = 0; // 下 var bodyBottom:b2BodyDef = new b2BodyDef(); bodyBottom.position.Set(centerX, centerY * 2); var BottomShapeDef:b2PolygonDef = new b2PolygonDef(); BottomShapeDef.SetAsBox(centerX, 0.2); BottomShapeDef.density = 0; // 右 var bodyRight:b2BodyDef = new b2BodyDef(); bodyRight.position.Set(centerX * 2, centerY); bodyRight.angle = Math.PI; var rightShapeDef:b2PolygonDef = new b2PolygonDef(); rightShapeDef.SetAsBox(0.2, centerY); rightShapeDef.density = 0; // 左 var bodyLeft:b2BodyDef = new b2BodyDef(); bodyLeft.position.Set(0, centerY); bodyLeft.angle = Math.PI; var leftShapeDef:b2PolygonDef = new b2PolygonDef(); leftShapeDef.SetAsBox(0.2, centerY); leftShapeDef.density = 0; var top:b2Body = m_world.CreateBody(bodyTop); top.CreateShape(topShapeDef); var bottom:b2Body = m_world.CreateBody(bodyBottom); bottom.CreateShape(BottomShapeDef); var right:b2Body = m_world.CreateBody(bodyRight); right.CreateShape(rightShapeDef); var left:b2Body = m_world.CreateBody(bodyLeft); left.CreateShape(leftShapeDef); // 描画設定 var debugDraw:b2DebugDraw = new b2DebugDraw(); debugDraw.m_sprite = this; debugDraw.m_drawScale = DRAW_SCALE; debugDraw.m_fillAlpha = 0.3; debugDraw.m_lineThickness = 1; debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit; m_world.SetDebugDraw(debugDraw); // イベントハンドラの登録 addEventListener(Event.ENTER_FRAME, enterFrameHandler); stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler); stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); // コンタクトリスナ var contactListener:ContactListener = new ContactListener(); contactListener.parent = this; m_world.SetContactListener(contactListener); } ////////////////////////////////////////////////////////////////////////////// // 自分の作成 ////////////////////////////////////////////////////////////////////////////// private function createMy():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.x = 10; bodyDef.position.y = 15; circleDef = new b2CircleDef(); circleDef.radius = 1.66; circleDef.density = 0.3; circleDef.friction = 0.2; circleDef.restitution = 0.5; bodyDef.userData = new my(); bodyDef.userData.id = 'id_my'; bodyDef.userData.name = 'na_my'; bodyDef.userData.enable = true; bodyDef.userData.width = 100; bodyDef.userData.height = 100; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetMassFromShapes(); addChild(bodyDef.userData); // ジョイントの定義 mouseJointDef = new b2MouseJointDef(); mouseJointDef.body1 = m_world.GetGroundBody(); mouseJointDef.body2 = body; mouseJointDef.target = body.GetWorldCenter(); mouseJointDef.maxForce = 30; mouseJointDef.timeStep = 1 / 24; } ////////////////////////////////////////////////////////////////////////////// // ボスの作成 ////////////////////////////////////////////////////////////////////////////// private function createBoss():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.x = 13.5; bodyDef.position.y = 4; boxDef = new b2PolygonDef(); boxDef.SetAsBox(312.5 / 2 / DRAW_SCALE, 200 / 2 / DRAW_SCALE); boxDef.density = 0; bodyDef.userData = new boss(); bodyDef.userData.id = 'id_boss'; bodyDef.userData.name = 'na_boss'; bodyDef.userData.enable = true; bodyDef.userData.width = 312.5; bodyDef.userData.height = 200; body = m_world.CreateBody(bodyDef); body.CreateShape(boxDef); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // 敵1の作成 ////////////////////////////////////////////////////////////////////////////// private function createEnemy1():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(25.5 / 2, 2); circleDef = new b2CircleDef(); circleDef.radius = 1.16; circleDef.density = 0.8; circleDef.friction = 0; circleDef.restitution = 1; bodyDef.userData = new enemy(); bodyDef.userData.id = 'id_enemy1'; bodyDef.userData.name = 'na_enemy1'; bodyDef.userData.enable = true; bodyDef.userData.width = 70; bodyDef.userData.height = 70; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetLinearVelocity(new b2Vec2(5, 0)); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // 敵2の作成 ////////////////////////////////////////////////////////////////////////////// private function createEnemy2():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(25.5 / 2, 2); circleDef = new b2CircleDef(); circleDef.radius = 1.16; circleDef.density = 0.8; circleDef.friction = 0; circleDef.restitution = 1; bodyDef.userData = new enemy(); bodyDef.userData.id = 'id_enemy2'; bodyDef.userData.name = 'na_enemy2'; bodyDef.userData.enable = true; bodyDef.userData.width = 70; bodyDef.userData.height = 70; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetLinearVelocity(new b2Vec2(5, 0)); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // 敵3の作成 ////////////////////////////////////////////////////////////////////////////// private function createEnemy3():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(25.5 / 2, 2); circleDef = new b2CircleDef(); circleDef.radius = 1.16; circleDef.density = 0.8; circleDef.friction = 0; circleDef.restitution = 1; bodyDef.userData = new enemy(); bodyDef.userData.id = 'id_enemy3'; bodyDef.userData.name = 'na_enemy3'; bodyDef.userData.enable = true; bodyDef.userData.width = 70; bodyDef.userData.height = 70; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetLinearVelocity(new b2Vec2(5, 0)); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // 仲間1の作成 ////////////////////////////////////////////////////////////////////////////// private function createFriend1():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(25.5 / 2, 2); circleDef = new b2CircleDef(); circleDef.radius = 1.16; circleDef.density = 0.1; circleDef.friction = 0; circleDef.restitution = 1; bodyDef.userData = new friend(); bodyDef.userData.id = 'id_friend1'; bodyDef.userData.name = 'na_friend1'; bodyDef.userData.enable = true; bodyDef.userData.width = 70; bodyDef.userData.height = 70; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetLinearVelocity(new b2Vec2(5, 0)); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // 仲間2の作成 ////////////////////////////////////////////////////////////////////////////// private function createFriend2():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(25.5 / 2, 2); circleDef = new b2CircleDef(); circleDef.radius = 1.16; circleDef.density = 0.1; circleDef.friction = 0; circleDef.restitution = 1; bodyDef.userData = new friend(); bodyDef.userData.id = 'id_friend2'; bodyDef.userData.name = 'na_friend2'; bodyDef.userData.enable = true; bodyDef.userData.width = 70; bodyDef.userData.height = 70; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetLinearVelocity(new b2Vec2(5, 0)); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // 仲間3の作成 ////////////////////////////////////////////////////////////////////////////// private function createFriend3():void{ var body:b2Body; var bodyDef:b2BodyDef; var boxDef:b2PolygonDef; var circleDef:b2CircleDef; bodyDef = new b2BodyDef(); bodyDef.position.Set(25.5 / 2, 2); circleDef = new b2CircleDef(); circleDef.radius = 1.16; circleDef.density = 0.1; circleDef.friction = 0; circleDef.restitution = 1; bodyDef.userData = new friend(); bodyDef.userData.id = 'id_friend3'; bodyDef.userData.name = 'na_friend3'; bodyDef.userData.enable = true; bodyDef.userData.width = 70; bodyDef.userData.height = 70; body = m_world.CreateBody(bodyDef); body.CreateShape(circleDef); body.SetLinearVelocity(new b2Vec2(5, 0)); body.SetMassFromShapes(); addChild(bodyDef.userData); } ////////////////////////////////////////////////////////////////////////////// // ジョイントの処理 ////////////////////////////////////////////////////////////////////////////// private function mouseDownHandler(event:MouseEvent):void { mouseJoint = b2MouseJoint(m_world.CreateJoint(mouseJointDef)); } private function mouseUpHandler(event:MouseEvent):void { m_world.DestroyJoint(mouseJoint); mouseJoint = null; } private function mouseMoveHandler(event:MouseEvent):void { if (mouseJoint) { var x:Number = event.stageX / DRAW_SCALE; var y:Number = event.stageY / DRAW_SCALE; mouseJoint.SetTarget(new b2Vec2(x, y)); } } public function Update(e:Event):void{ m_world.Step(m_timeStep, m_iterations); for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next){ if (bb.m_userData is Sprite){ bb.m_userData.x = bb.GetPosition().x * 30; bb.m_userData.y = bb.GetPosition().y * 30; bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI); if (bb.m_userData.enable == false) { m_world.DestroyBody(bb); removeChild(getChildByName(bb.m_userData.name)); } } } } ////////////////////////////////////////////////////////////////////////////// // 衝突時の処理 ////////////////////////////////////////////////////////////////////////////// public function addContactEffect(point:b2ContactPoint):void { // 衝突したシェイプ var s1:b2Shape = point.shape1; var s2:b2Shape = point.shape2; // 衝突したボディ var b1:b2Body = s1.m_body; var b2:b2Body = s2.m_body; if (b1.m_userData && b2.m_userData) { // ボスと衝突した if ((b1.m_userData.id == "id_my" && b2.m_userData.id == "id_boss") || (b2.m_userData.id == "id_my" && b1.m_userData.id == "id_boss")) { // 斬撃の画像のサイズと位置のセットアップ var zanImage:Bitmap = new ZanImage(); zanImage.width = 50; zanImage.height = 50; zanImage.x = -zanImage.width / 2; zanImage.y = -zanImage.height / 2; var spritez:Sprite = new Sprite(); spritez.x = point.position.x * DRAW_SCALE; spritez.y = point.position.y * DRAW_SCALE; spritez.addChild(zanImage); addChild(spritez); var anglez:Number = Math.random() * 360; var lengthz:Number = Math.random() * 100 + 50; var dxz:Number = spritez.x + lengthz * Math.cos(anglez); var dyz:Number = spritez.y + lengthz * Math.sin(anglez); // Tweenerで斬撃を飛ばす Tweener.addTween(spritez, { time: 3, scaleX: 0, scaleY: 0, alpha: 0, rotation: 600, x: dxz, y: dyz, onComplete: function():void { removeChild(spritez); } }); var i:int = int(lp_txt.text); i = i-20; lp_txt.text = String(i); } } } ////////////////////////////////////////////////////////////////////////////// // 時間経過ごとの処理 ////////////////////////////////////////////////////////////////////////////// private function onTimer(e:TimerEvent):void{ var i:int = int(disp_txt.text); i = i-1; disp_txt.text = String(i); switch (i) { case 25 : createFriend1(); break; case 20 : createEnemy2(); break; case 15 : createFriend2(); break; case 10 : createEnemy3(); break; case 5 : createFriend3(); break; } } private function enterFrameHandler(event:Event):void { m_world.Step(1 / 24, 10); } public var m_world:b2World; public var m_iterations:int = 10; public var m_timeStep:Number = 1.0/30.0; } }
ContactListener.as
package { import Box2D.Collision.b2ContactPoint; import Box2D.Dynamics.b2ContactListener; public class ContactListener extends b2ContactListener { public var parent:game05; public function ContactListener() { } public override function Add(point:b2ContactPoint):void { var num:int = 10 + 1; if (num > 10) { num = 10; } for (var i:int = 0; i < num; ++i) { parent.addContactEffect(point); } } } }
コメント