めも

private import SDL;
private import opengl;
private import openglu;
private import std.math;

void main()
{
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		throw new Error("SDL Init Failed.");
	}
	SDL_Surface* screen = SDL_SetVideoMode(640, 480, 0, SDL_OPENGL);
	
	// OpenGL初期化
	glLoadIdentity();
	glMatrixMode(GL_PROJECTION);
	glViewport(0, 0, 640, 480);
	gluPerspective(30, 640.0/480, 1, 1000);

	glClearColor(0, 0, 0, 0);
	// イベントループ
	float x, y;
	x = 0, y = 0;
	
	float r = 0;
	bool done = false;
	SDL_Event e;
	while ( !done ) {
		while ( SDL_PollEvent(&e) ) {
			done = e.type == SDL_QUIT;
		}
		glClear(GL_COLOR_BUFFER_BIT);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		gluLookAt(0, 480, 50, 0, 0, 0, 0, 1, 0);
		drawWall();

		if(isPress(SDLK_LEFT))  x -= 5;
		if(isPress(SDLK_UP))    y -= 5;
		if(isPress(SDLK_RIGHT)) x += 5;
		if(isPress(SDLK_DOWN))  y += 5;
		glTranslatef(x, 0, y);
		r += 1;
		glRotated(r, 0, 5, 0);
		
		
		glBegin(GL_POLYGON);
		{
			float size = 12;
			glColor3f(1, 0, 0);
			glVertex3d(-size/2, 0, -size/2);
			glColor3f(0, 1, 0);
			glVertex3d(size/2,  0, -size/2);
			glColor3f(0, 0, 1);
			glVertex3d(size/2,  0, size/2);
			glColor3f(1, 1, 0);
			glVertex3d(-size/2, 0, size/2);
		}
		glEnd();
		
		glFlush();
		SDL_GL_SwapBuffers();
		SDL_Delay(1000/30);
	}
	SDL_Quit();

}

void drawWall()
{
	float w = 160;
	float h = 240;
	foreach(y; [-10.0, 10.0])
	{
		drawLine(-w/2, y, -h/2,  w/2, y, -h/2);
		drawLine( w/2, y, -h/2,  w/2, y,  h/2);
		drawLine( w/2, y,  h/2, -w/2, y,  h/2);
		drawLine(-w/2, y,  h/2, -w/2, y, -h/2);
	}
}

void drawLine(float x1, float y1, float z1, float x2, float y2, float z2)
{
	glBegin(GL_LINES);
	{
		glVertex3d(x1, y1, z1);
		glVertex3d(x2, y2, z2);
	}
	glEnd();
}

bool isPress(int id)
{
	Uint8* keys = SDL_GetKeyState(null);
	return keys[id] == SDL_PRESSED;
}

RectWinder感想続きの感想

おめがさんが、濃い内容の感想続きを書いてくれたので、それに対する感想(いいわけ?)を、、。
 

「打ち返し」が非常に強力なんだけど、
前述のように敵弾が散発的にしかこないので無駄撃ちは厳禁。
打ち返しの連射をするためには、
1発の発射で必ず1機の中型きを落としてクイックリロードを成功させる必要がある。
要求されるのは「敵弾幕の把握」と「打ち返し発動タイミング」。

ここなんですよね。やりたかったのは。

  • 弾幕の把握
  • 打ち返し発動タイミング

kenmoはピンクが、

高速レーザーのような回避困難な攻撃に対して、(それを覚えて・予測して)
ローズクラッカーをタイミングよく発動させる

というゲーム性に面白みを感じていたので、
それに特化した感じです。
 
ただ、

結果的に「敵弾をどこに、どれだけ撃たせるか」までを含めたパターン化が必要になる。
上記の要素のうち、どれか一つをミスると、敵弾の増加、打ち返し不能といった致命的状況に落ち込まれる。
平均台の上でバランス崩すと、即落下みたいな。振り落とされないようにする印象。

というのはやりすぎですね。
 
タイミングゲー、ということで少しだけトレジャーの影響を受けているかも、ですが
例えば、エイリアンソルジャーの場合、ミスがジリ貧につながるけど、
弾をカウンターフォースで喰い続けていれば、逆転が可能です。
しかし、RectWinderはそれがないですね。
とにかく逆転の要素が見つからないなー、と。
 

いくつか感じるのはkenmoさんのゲームは「誘導」が足りないと思う。
ほんのりと解法を匂わせるとかそういう…、センス?テクニック?
多少露骨で良いので、プレーヤーが見つけて
「はは〜ん、見つけたぞ!そういうことか!」
とニヤニヤできるようにしておく。
プレーヤーが自分で見つけた発見は、プレイのモチベーションに繋がる。
露骨さをコントロールできれば、発見に難易度がつけれるのでより良い。

「誘導」という点を「打ち返し」で言えば、
ギガウィングラジルギもマーズマトリックスも未プレイなので、それらとの比較ができないのですが、
WispLispで言えば、打ち返し(弾喰いチャージ⇒発射)が前方発射のみなので、
戦略が立てやすい作りになっていますね。
 
その点、RectWinderは、打ち返し方向に自由度を持たせているのですが、
「その方向を操作している余裕がない」ので、結局前方が安定になってしまっています。
 
そこを本当に楽しませたいならば、
レベルデザインでうまく調整する必要がありますね。
 
具体的には、
「その方向を操作している余裕がない」ならば、
「特定の方向にグリッドを向けていることが有利な状況」が「継続」するとか。
 
例えば、敵のアルゴリズムが、
1.その場に停止(もしくはゆっくり移動)
2.狙い撃ち弾
という行動を取り続けるならば、敵の方向にグリッドを向けて、
打ち返し狙いをすれば、安定ですよね。
 
そして、その方向を変えることなく、打ち返しを行えるような敵の出現パターンにする。

そうすると、自機の移動のみで、打ち返しで敵を撃破できるようになります。
 
なんとなくですが、
グリッドの操作の特性から考えると、「継続」っていうのがキーワードになるような気もします。
 

もう一つは「選択肢」。
例えば、yes/noの選択肢があるアドベンチャーゲームがあるとしよう。
普通ならyesの後のストーリーも、noの後のストーリーも作り調整するハズ。
これはシューティングでも同様で、アイテムを取った/取らない、中型を倒した/倒さない、
それぞれ両方の状況を考慮する必要がある。
今回の例だと、アイテムを取れなかった/打ち返しを外した状態が極端に不利になる。
この部分は未調整のように感じました。

うまくいくこと前提なんですよね。
それで、本流から外れると、即バットエンド。
 
これじゃ、プレイヤーを納得させることはできないですよね。
 
「なぜ、ミスしたかの理由をプレイヤーに理解・納得させる」
 
ゲーム作りの基本ですね、、。はい。
 

ただ、逆に考えればスペランカー/プリンスオブペルシャばりの、
「基本行為が一撃死を含むような」個性的な特徴を持つゲームとも言える。

kenmo的には、スペランカープリンスオブペルシャも良ゲーなので、
そこらへんの趣向がモロに出ている感じですね。
 
もう少し、一般ユーザーの考えも理解しないと……。
ショット時の自機の移動が遅すぎるのも、一般的な感覚が無いためですね。
虫姫さまふたり」とかもそんなに遅くなるわけじゃないし……。
 

下部分は表示がゲージと被るので、進入不可と認識するか、入りたくない場所として認識すると思います。

これも後付け仕様の弊害か、、。
ゲージは、プレイの邪魔にならないよう配置しないと、、。
 

バグ技発見。
1フレーム中に同種類の弾を複数発当てて敵を倒すと、当てた分の点数が入る/アイテムが出るっぽい。
偶然見つけた後、ソースコード上でも確認した。

敵の当たり判定ループで、ヒット時にbreakしてないという、
しょーもないバグですね、、。
 
 
 
なにはともあれ、おめがさんには楽しんで(苦しんで?)もらえたみたいで光栄ですねー。
作者冥利に尽きます。はい。

RECT WINDERの感想を書いてもらえた

弾幕打ち返しシュー RECT WINDERの感想をおめがさんが書いてくれました。
http://d.hatena.ne.jp/o_mega/20061107
 
すごい参考になります。
 
あと、スクリーンショットを見ると、発狂モード(TIME:2300で開始)を乗り越えられているようで、
結構やりこんでもらえたみたいです。
ありがたやー。
 
 
 
以下、感想に対する感想です。
 
限られた時間で作ったためか、kenmoの悪い癖がでまくりでした。
良くも悪くもトガリ過ぎというか……。

・ショット低速が異様に遅く、ショット発射状態では有効な回避はできない
・判定が広め。グラフィックと同サイズ
・弾は極力避けないパターンを構築する
・ミス時に画面内にパワーアップがない/近いうちに自爆する中型がいないと、諦めモード。

ここらへんって、特に、弾幕避けを期待している人にはガックリきますよね。
弾避けらんないもん。
 
まー、弾幕避けが嫌い、というkenmoの負のパワーをぶつけすぎました。
確かに、弾幕シューというより、ガチの解法を模索していくパズルゲーに近いですね。
 
もー、作っているうちは自分の世界に入り込みすぎて、全然気づきませんでした。
もう少し特性を分析して慎重に作らないと。
 
 

グリッドなしでの復活は、通常のプレイより困難で初心者にとっては効果が薄いと感じます。
また、ゲームの主題でもある「打ち返し」システムをなくしてしまうことは本末転倒になってるのでは…

後付け仕様の弊害ですね。
 
最近、
「ボムが切れた後のボムボタンって無駄だよね」
と思っていたのですが、
「グリッドがなくなったときの、グリッドボタンって無駄だよね」
と同じことが言えることに、身をもって気づかされました……。
うーむ。
 
しかも、ゆるいシステムと書いておきながら、全然ゆるくない。
kenmoは
「ギリギリの状態で粘れる」
というゲーム性が好きなのですが、それをすっかり忘れてました。
もったいないことをしました。
 
とにかく、もう少し、初心者救済要素が欲しいところですね。
 
あと、後付け仕様の影響をもう少し分析しておけば……。
 
 

慣れない人だと、多分、第二形態(両サイド横撃ち)でがっくり来るんじゃないかなぁ。
ちょっとあの攻撃はコンスタントに避けれる気がしない。

確かに……。
あれで被弾して最弱状態になって、次の4-5way×3+ザコ突撃って、ハメコンボですよね。
 
まあ、第二形態(両サイド横撃ち)は画面の一番上か一番下で回避できるけど、
(※第三形態も画面一番上でコンコン避けで回避可能)
そんなこと分かるわけないし。
 
パズルゲーならパズルゲーらしく、もう少し解法を分かりやすくする方向性もありかもしれないですね。
 
 

解法が強く制限されていて、それ以外の攻略法のフォローが無い印象。
ショットのパワーアップ曲線、打ち返しのリロード時間等。

なるほどー。
確かに、キモとなる「ショット」と「打ち返し」が極端なEnum型なんですよね。
これはシビアすぎ&自由度なさ過ぎ。
Int型にして、もう少しゆるめにしないと、「これは無理!」と投げられそうですね。
 
 
 
いや、本当に参考になりました。
ありがとうごじゃりますー。

お正月ゲー

ヘルメンバーによるゲーム集「ゲームのはこづめ」がまた出るそうです。
http://www5.atwiki.jp/yaruhara/pages/77.html
 
今回のお題は「お正月」!
なんて面白いことを考えるんだ!!
 
とりあえず「お正月」のキーワードを考えてみる。

アイテム

これがあればお正月!

  • お餅・鏡餅
  • 門松
  • 年賀状
  • お雑煮
  • お年玉
  • 初日の出
  • 七福神

遊び・行事

  • 独楽回し
  • メンコ
  • かるた
  • 餅つき
  • 双六
  • 福笑い
  • おみくじ
  • たこあげ
  • 羽子板
  • 書き初め
  • 獅子舞
  • 初詣で
  • 初夢

 
でも、「新春〜」てつけば、なんでもお正月だよね。
 
「新春クイズ」
とか、
「新春かくし芸」
とか、
「新春シューティング」
とか、
「新春サイパワー」
とか。

RECT WINDERあとがき

せっかく作ったんだから、反省文でも書いときましょう。
次につながるように。
 
 

コンセプト

作りたかったのは、上下移動でショット角度がぐりぐり動くのと、打ち返し。
 
ただ、kenmo的には「打ち返し」の方が重要だったので、
レベルデザインは「打ち返し」が強めで、ショットはおまけ。(パワーアップすればそれなり使えるけど)
 
かかった時間は1日半ほどで。
まずはショット角度が動くところから作って、打ち返しを入れるべきかちょっと悩みました。
理由は「ショット角度が動く」というフォーメーション変化系は、それだけでも使いこなすのが難しいから。
 
ただ、打ち返しがないとkenmo的に面白くなかったので、頑張って入れました。
 
その結果、まあ、ショット角度のレベルデザインは前方向安定で、ときどき角度を変えてみるのがいいかも、
というゆるい感じになりました。
 
この適当さは反省点ですね。
 
 
あと、最初は一発死だったけど、
「そういえばパワーアップ系はやったことないなー」
と思い、ショット強化アイテムを出現させて、
、、気が付いたらパーツが壊れる仕組みになっていました。
まー、魔界村のアーマーみたいな感じで一回だけは大丈夫!
ダメージ性のシューティングって、ゆるくていいですね!
 
あと、ダメージでボム発動も気づいたらこうなってた(w
ダメージ後、数フレーム無敵というのが、現実離れして個人的に好きでないので、こうなっちゃいました。
ただ、その分、敵に衝突すると、死亡確定ですが……。
 
 
あと、弾幕
kenmoの知っている弾幕を力の限りに詰め込みました。
ただ、冷静に見ると、どうもありがちで面白くない。
もっと、弾幕を研究せねば、、。
 
 

D言語

今時の言語らしからぬ、
「1つのファイルにクラスを何個も書ける」
という特徴は、
「とりあえず動けばいい」
という趣味プログラムを書くぶんには凄い便利。
そのぶん、「{」の対応が合ってません、
とかいうエラーが出ると、泣きそうになるけれども…(w
 

設計

トークン管理の部分は、libBulletMLの組み込み方法を解析するときに参考にしたABAさんのコードを真似してみた。
テンプレートは便利じゃのー。
あと、各トークンに親のインスタンスをスタティックで持たせるのもいいですね。
 
 

RECT WINDER

RECT WINDER

http://www5f.biglobe.ne.jp/~kenmo/dest/d/rectwinder.lzh
弾幕打ち返しシューティング。
○操作方法
・Zキー/1ボタン:ショット
・Xキー/2ボタン:打ち返し
F9でフルスクリーン・ウィンドウモード切替
ジョイスティック推奨です。
 
○更新

  • ジョイスティックがささっていないと起動できないという、しょーもないバグを修正
  • フルスクリーンモード時に一部ビデオカードで落ちるバグに対応するためウィンドウサイズ「640x480」で起動できるようにバッチファイルを追加(そもそも「320x480」なんてウィンドウサイズにしたのが間違いですがー)