« 曲がるレーザーの実装実験(5/6) | トップページ | タイルマップ座標のオフセットを求める »

2011年6月17日 (金)

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

高速化を図ってみた。

曲がるレーザー 500本あたりでややコマ落ち

ノードを双方向リストにして、履歴をコピーするコストを無くした。

ループはポインタを進めるようにした。

結果は前回より若干速くなった気がする程度。Releaseビルドでもほとんど変化無い。

メッシュでレーザー一本分をいっぺんに描画すればもっと速くなると思うけど(隙間も出なくなるし)、DXライブラリではここらが限界か。

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
{
	Node *next, *prev;
	Fixed cx, cy; // 中心座標
	Fixed ux, uy; // 進行方向の単位ベクトル
};

struct Head
{
	Node *head; // 先頭ノード
	Node *tail; // 最後尾ノード
	Fixed speed;  // 移動速度
	Radian angle; // 進行方向の角度
};

static const int HEAD_NUM = 512;
static const int LINK_NUM = 16;
static struct Head head[HEAD_NUM];
static struct Node node[HEAD_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<HEAD_NUM; ++i) {
		head[i].speed = 10;
		head[i].angle = 0;
		head[i].head = &node[i][0];
		head[i].tail = &node[i][LINK_NUM-1];

		node[i][0].cx = GetRand(sx-1);
		node[i][0].cy = GetRand(sy-1);
		node[i][0].ux = cos(head[i].angle);
		node[i][0].uy = sin(head[i].angle);
		node[i][0].next = NULL;
		node[i][0].prev = NULL;

		for (j=1; j<LINK_NUM; ++j) {
			node[i][j] = node[i][j-1];
			node[i][j-1].next = &node[i][j];
			node[i][j].prev = &node[i][j-1];
		}
	}

	// レーザーテクスチャ画像をロード
	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()
{
	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;

	Head *head_end = &head[HEAD_NUM];
	for (Head *head_ptr = &head[0]; head_ptr < head_end; ++head_ptr) {

		Node *node_ptr = head_ptr->tail;
		// 新しい先頭ノードは最後尾のノードを切り離したもの
		node_ptr->prev->next = NULL;
		head_ptr->tail = node_ptr->prev;

		// ターゲットへ向けて旋回
		CFixed ax = target_x - head_ptr->head->cx;
		CFixed ay = target_y - head_ptr->head->cy;
		CFixed bx = head_ptr->head->ux;
		CFixed by = head_ptr->head->uy;
		if (ax*by-ay*bx < 0) {
			// 正方向に回転
			head_ptr->angle += M_PI/24;
		}
		else {
			// 逆方向に回転
			head_ptr->angle -= M_PI/24;
		}

		// 進行方向に移動
		node_ptr->ux = cos(head_ptr->angle);
		node_ptr->uy = sin(head_ptr->angle);
		node_ptr->cx = head_ptr->head->cx + node_ptr->ux * head_ptr->speed;
		node_ptr->cy = head_ptr->head->cy + node_ptr->uy * head_ptr->speed;

		// 先頭ノードに登録
		node_ptr->prev = NULL;
		node_ptr->next = head_ptr->head;
		head_ptr->head->prev = node_ptr;
		head_ptr->head = node_ptr;


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

		cross_count = 0;

		for (node_ptr = head_ptr->head; node_ptr != NULL; node_ptr = node_ptr->next) {
			int cx = node_ptr->cx;
			int cy = node_ptr->cy;
			int ax = node_ptr->ux * 4;
			int ay = node_ptr->uy * 4;

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

			if (node_ptr == head_ptr->head) {
				// 頭の蓋
				if (isCrossSegment(pt[0], pt[1], pt[2], pt[3])) ++cross_count;
			}
			else if (node_ptr == head_ptr->tail) {
				// 尻尾の蓋
				if (isCrossSegment(pt[0], pt[1], pt[2], pt[3])) ++cross_count;
			}
			if (node_ptr->prev != NULL) {
				// 胴体の脇
				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()
{
	ClearDrawScreen();

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

	Head *head_end = &head[HEAD_NUM];
	for (Head *head_ptr = &head[0]; head_ptr < head_end; ++head_ptr) {

		int bcx, bcy;
		int bax, bay;

		for (Node *node_ptr = head_ptr->head; node_ptr != NULL; node_ptr = node_ptr->next) {

			int cx = node_ptr->cx;
			int cy = node_ptr->cy;
			int ax = node_ptr->ux * 4;
			int ay = node_ptr->uy * 4;

			// 前後のノード間にテクスチャ画像を貼る
			if (node_ptr == head_ptr->head->next) {
				// 頭
				DrawModiGraph(bcx+bay, bcy-bax, cx+ay, cy-ax, cx-ay, cy+ax, bcx-bay, bcy+bax, graph_laser[0], TRUE);
			}
			else if (node_ptr == head_ptr->tail) {
				// 尻尾
				DrawModiGraph(cx-ay, cy+ax, bcx-bay, bcy+bax, bcx+bay, bcy-bax, cx+ay, cy-ax, graph_laser[0], TRUE);
			}
			else if (node_ptr->prev != NULL) {
				// 胴体
				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;
		}
	}
}

|

« 曲がるレーザーの実装実験(5/6) | トップページ | タイルマップ座標のオフセットを求める »

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

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

コメント

コメントを書く



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




« 曲がるレーザーの実装実験(5/6) | トップページ | タイルマップ座標のオフセットを求める »