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);
}
}
}
}

コメント