Chapter 06

スプライト同士の衝突(1対1)

かじるプログラミング
かじるプログラミング
2022.10.04に更新

スプライト同士の衝突(1対1)

今回は1対1の衝突についてのお話です。
スプライト同士の衝突を判定し、跳ね返りをさせてみましょう。

スプライト一つだけでは衝突を実現する事は不可能ですので、
もう一つ別のスプライトを用意します。

画像セットを3パターンづつ用意したので、これらをお使いください。

霊夢(BAD)


reimu_bad_01.png


reimu_bad_02.png


reimu_bad_03.png

魔理沙(GOOD)


marisa_good_01.png


marisa_good_02.png


marisa_good_03.png

魔理沙(BAD)


marisa_bad_01.png


marisa_bad_02.png


marisa_bad_03.png

ここからは、次のコードをベースにして話を進めます。

let reimu, marisa;// スプライト

function preload(){

	// アニメーション
	loadAni("r_good", "reimu_good_01.png", 3);
	loadAni("r_bad", "reimu_bad_01.png", 3);
	loadAni("m_good", "marisa_good_01.png", 3);
	loadAni("m_bad", "reimu_bad_01.png", 3);
}

function setup(){
	createCanvas(windowWidth, windowHeight);
	angleMode(DEGREES);
	frameRate(32);
	noSmooth();
	noStroke();

	// スプライト(霊夢)
	reimu = new Sprite(width/2-200, height/2, 45);
	reimu.shapeColor = color("white");
	reimu.ani = "r_good";
	reimu.scale = 4;

	// スプライト(魔理沙)
	marisa = new Sprite(width/2+200, height/2, 45);
	marisa.shapeColor = color("white");
	marisa.ani = "m_good";
	marisa.scale = 4;
}

function draw(){
	background(33);

	// 全てのスプライトを調べる
	for(let sprite of allSprites){
		// キャンバスの外に出たら反対側へ移動させる(4方向)
		if(width < sprite.x) sprite.x = 0; // 右から出たら
		if(sprite.x < 0) sprite.x = width; // 左から出たら
		if(height < sprite.y) sprite.y = 0;// 下から出たら
		if(sprite.y < 0) sprite.y = height;// 上から出たら
	}

	// Debug
	allSprites.debug = mouse.pressing();
}

ちょうど良い距離に2つのスプライトが並んでいますね。
(何かが起こりそうな予感)

スプライト同士の衝突

2つのスプライトを衝突させてみましょう。
左のスプライトを右の方向に向かって移動させるだけです。

// 省略

function setup(){
	createCanvas(windowWidth, windowHeight);
	angleMode(DEGREES);
	frameRate(32);
	noSmooth();
	noStroke();

	// スプライト(霊夢)
	reimu = new Sprite(width/2-200, height/2, 45);
	reimu.shapeColor = color("white");
	reimu.ani = "r_good";
	reimu.scale = 4;
	reimu.speed = 6;// 速度
	reimu.direction = 0;// 角度

	// スプライト(魔理沙)
	marisa = new Sprite(width/2+200, height/2, 45);
	marisa.shapeColor = color("white");
	marisa.ani = "m_good";
	marisa.scale = 4;
}

// 省略

霊夢にどつかれて飛ばされる魔理沙です。

スプライトの3つのモード

スプライトには"none"と"dynamic"、"static"という3つのモードが存在します。
簡単に説明すると、"dynamic"は動くスプライト、"static"は固定され動かないスプライトです。

モード 意味
none 何にも衝突しないスプライト
dynamic 動くスプライト
static 固定されたスプライト

スプライトを生成するタイミングで次の様にして指定します。
(指定しない場合は"dynamic"になります)

スプライト = new Sprite(x座標, y座標, 直径, "none");// 何にも衝突しないスプライト
スプライト = new Sprite(x座標, y座標, 直径, "dynamic");// 動くスプライト
スプライト = new Sprite(x座標, y座標, 直径, "static");// 固定されたスプライト

試しに、霊夢を"dynamic"、魔理沙を"static"にして実行してみます。

// 省略

function setup(){
	createCanvas(windowWidth, windowHeight);
	angleMode(DEGREES);
	frameRate(32);
	noSmooth();
	noStroke();

	// スプライト(霊夢)
	reimu = new Sprite(width/2-200, height/2, 45, "dynamic");
	reimu.shapeColor = color("white");
	reimu.ani = "r_good";
	reimu.scale = 4;
	reimu.speed = 6;// 速度
	reimu.direction = 0;// 角度

	// スプライト(魔理沙)
	marisa = new Sprite(width/2+200, height/2, 45, "static");
	marisa.shapeColor = color("white");
	marisa.ani = "m_good";
	marisa.scale = 4;
}

// 省略

霊夢にどつかれても耐える魔理沙です。

衝突したら...

"collide関数"を利用する事で、衝突を検出する事ができます。
第二引数には、衝突時に実行する処理をコールバックとして記述します。
(引数はそれぞれ、a:スプライトA, b:スプライトBです)

スプライトA.collide(スプライトB, (a, b)=>{
	// 衝突した時の処理(a:スプライトA, b:スプライトB)
});

衝突したタイミングで、2つのスプライトのアニメーションを変更してみます。
アニメーションの変更方法は次の通りです。

スプライト.ani = アニメーション名;

これらを組み合わせたコードは次の通りです。

// 省略

function setup(){
	createCanvas(windowWidth, windowHeight);
	angleMode(DEGREES);
	frameRate(32);
	noSmooth();
	noStroke();

	// 省略

	// スプライト同士の衝突
	reimu.collide(marisa, (a, b)=>{
		a.ani = "r_bad";// 霊夢BAD
		b.ani = "m_bad";// 魔理沙BAD
	});
}

// 省略

衝突すると、霊夢と魔理沙のアニメーションが変わります。

接触したら...

"overlap関数"を利用する事で、接触を検出する事ができます。
第二引数には、接触時に実行する処理をコールバックとして記述します。
(引数はそれぞれ、a:スプライトA, b:スプライトBです)

先程の"collide関数"と同じ様に使えますが、
こちらの関数を使う事で、2つのスプライトは衝突せずに通過する様になります。

スプライトA.overlap(スプライトB, (a, b)=>{
	// 接触した時の処理(a:スプライトA, b:スプライトB)
});

魔理沙の後ろを通り過ぎていく霊夢。

次回は1対多の衝突についてのお話です。