« 曲がるレーザーの実装実験(4/6) | トップページ | 曲がるレーザーの実装実験(6/6) »

2011年6月16日 (木)

曲がるレーザーの実装実験(5/6)

当たり判定を実装してみた。

曲がるレーザー 当たってない判定 曲がるレーザー 当たってる判定

レーザーの輪郭で構成される多角形の内側に、鼻(1ピクセル)が入っていれば当たり。

ウチの環境(Core 2 Duo E6850 3.0GHz, GeForce GTS 250)で、500本出してコマ落ちするかしないかくらい。16連結だから8000キャラ相当。ベタなコードだしこんなものか。

曲がるレーザー顔マーク画像

顔マーク画像 face.png 64x32

CurveLaser.cpp

#include "DxLib.h"
#if 0
#define _USE_MATH_DEFINES
#include "math.h"
#define Fixed  double
#define CFixed double
#define Radian double
#else
#include "fixedmath.h"
#define sin   sin13
#define cos   cos13
#define atan2 atan21
#define Radian int
#endif

struct Node
{
	Fixed x, y;   // 中心座標
	Fixed speed;  // 移動速度
	Radian angle; // 進行方向
};

static const int NODE_NUM = 8;
static const int LINK_NUM = 16;
static struct Node node[NODE_NUM][LINK_NUM];

static int target_x, target_y;
static int target_face;
enum { FACE_NORMAL, FACE_CRY };

static int graph_laser[2]; // レーザーテクスチャ画像のハンドル
static int graph_face[2];  // 顔マーク画像のハンドル

/**************************************
 *  二本の線分が交わっているか判定
 */
static bool isCrossSegment(const POINT &p1, const POINT &p2, const POINT &p3, const POINT &p4)
{
	// p1,p2を結ぶ線分とp3,p4を結ぶ線分が交差しているときtrue
	int a1 = (p1.x-p2.x) * (p3.y-p1.y) + (p1.y-p2.y) * (p1.x-p3.x);
	int a2 = (p1.x-p2.x) * (p4.y-p1.y) + (p1.y-p2.y) * (p1.x-p4.x);
	if ((a1 < 0 && a2 > 0) || (a1 > 0 && a2 < 0)) {
		int a3 = (p3.x-p4.x) * (p1.y-p3.y) + (p3.y-p4.y) * (p3.x-p1.x);
		int a4 = (p3.x-p4.x) * (p2.y-p3.y) + (p3.y-p4.y) * (p3.x-p2.x);
		if ((a3 < 0 && a4 > 0) || (a3 > 0 && a4 < 0)) return true;
	}
	return false;
}

/**************************************
 *  初期化
 */
void CurveLaser_Initialize()
{
	int i, j;

	int sx = 640, sy = 480, cb;
	GetScreenState(&sx, &sy, &cb);

	// 画面内にランダムに配置
	for (i=0; i<NODE_NUM; ++i) {
		node[i][0].x = GetRand(sx-1);
		node[i][0].y = GetRand(sy-1);
		node[i][0].speed = 10;
		node[i][0].angle = 0;

		for (j=1; j<LINK_NUM; ++j) {
			node[i][j] = node[i][0];
		}
	}

	// レーザーテクスチャ画像をロード
	LoadDivGraph("laser.png", 2, 2, 1, 16, 16, graph_laser);
	// 顔マーク画像をロード
	LoadDivGraph("face.png", 2, 2, 1, 32, 32, graph_face);
}

/**************************************
 *  後始末
 */
void CurveLaser_Finalize()
{
}

/**************************************
 *  フレーム単位の更新
 */
void CurveLaser_Update()
{
	int i, j;
	POINT pt[6];
	int cross_count;

	// ターゲットはマウス座標
	GetMousePoint(&target_x, &target_y);

	pt[0].x = target_x;
	pt[0].y = target_y;
	pt[1].x = -100;
	pt[1].y = -100;
	target_face = FACE_NORMAL;

	for (i=0; i<NODE_NUM; ++i) {
		for (j=LINK_NUM-1; j>0; --j) {
			// 連結するノードはひとつ前の履歴
			node[i][j] = node[i][j-1];
		}

		// ターゲットへ向けて旋回
		CFixed ax = target_x - node[i][0].x;
		CFixed ay = target_y - node[i][0].y;
		CFixed bx = cos(node[i][0].angle);
		CFixed by = sin(node[i][0].angle);
		if (ax*by-ay*bx < 0) {
			// 正方向に回転
			node[i][0].angle += M_PI/24;
		}
		else {
			// 逆方向に回転
			node[i][0].angle -= M_PI/24;
		}

		// 進行方向に移動
		node[i][0].x += cos(node[i][0].angle) * node[i][0].speed;
		node[i][0].y += sin(node[i][0].angle) * node[i][0].speed;


		/********************************
		*  当たり判定
		*/

		cross_count = 0;

		for (j=0; j<LINK_NUM; ++j) {
			int cx = node[i][j].x;
			int cy = node[i][j].y;
			int ax = cos(node[i][j].angle) * 4;
			int ay = sin(node[i][j].angle) * 4;

			pt[2].x = cx+ay;
			pt[2].y = cy-ax;
			pt[3].x = cx-ay;
			pt[3].y = cy+ax;

			if (j == 0) { // 先頭
				if (isCrossSegment(pt[0], pt[1], pt[2], pt[3])) ++cross_count;
			}
			else if (j == LINK_NUM-1) { // 後尾
				if (isCrossSegment(pt[0], pt[1], pt[2], pt[3])) ++cross_count;
			}

			if (j > 0) { // 胴体
				if (isCrossSegment(pt[0], pt[1], pt[2], pt[4])) ++cross_count;
				if (isCrossSegment(pt[0], pt[1], pt[3], pt[5])) ++cross_count;
			}

			pt[4] = pt[2];
			pt[5] = pt[3];
		}
		if (cross_count % 2) target_face = FACE_CRY;
	}
}

/**************************************
 *  描画
 */
void CurveLaser_Render()
{
	int i, j;

	ClearDrawScreen();

	// ターゲットに顔マーク画像
	DrawGraph(target_x-15, target_y-15, graph_face[target_face], TRUE);

	for (i=0; i<NODE_NUM; ++i) {

		int bcx, bcy;
		int bax, bay;

		for (j=0; j<LINK_NUM; ++j) {

			int cx = node[i][j].x;
			int cy = node[i][j].y;
			int ax = cos(node[i][j].angle) * 4;
			int ay = sin(node[i][j].angle) * 4;

			// 前後のノード間にテクスチャ画像を貼る
			if (j == 1) {
				// 先頭
				DrawModiGraph(bcx+bay, bcy-bax, cx+ay, cy-ax, cx-ay, cy+ax, bcx-bay, bcy+bax, graph_laser[0], TRUE);
			}
			else if (j == LINK_NUM-1) {
				// 後尾
				DrawModiGraph(cx-ay, cy+ax, bcx-bay, bcy+bax, bcx+bay, bcy-bax, cx+ay, cy-ax, graph_laser[0], TRUE);
			}
			else if (j > 0) {
				// それ以外
				DrawModiGraph(bcx+bay, bcy-bax, cx+ay, cy-ax, cx-ay, cy+ax, bcx-bay, bcy+bax, graph_laser[1], TRUE);
			}

			bcx = cx;
			bcy = cy;
			bax = ax;
			bay = ay;
		}
	}
}

|

« 曲がるレーザーの実装実験(4/6) | トップページ | 曲がるレーザーの実装実験(6/6) »

C/C++」カテゴリの記事

DXライブラリ」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)




« 曲がるレーザーの実装実験(4/6) | トップページ | 曲がるレーザーの実装実験(6/6) »