Flashで物理演算を使ったミニゲーム その5「動かないBodyに衝突した時の処理」【Flash・lemonovel】

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ファイルと同じ階層に配置しました。
flash_020

フォルダ内には斬撃用の画像と衝突時の処理用のasを追加しました。
まとめると
「Box2D」フォルダ
「caurina」フォルダ
game05.fla
game05.as
Zangeki.png
ContactListener.as
こんな感じ。

flash_021
ステージ側は画像にて残り時間とボスの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」の数字を減らします。

flash_022
ポップアップでサンプル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);
			}
		}
	}
}

◆スポンサードリンク – 楽天市場
 

コメント

タイトルとURLをコピーしました