ガラスエフェクトの応用とスコアボーナス

アバター
SAI
記事: 115
登録日時: 14年前
住所: はひほーひ

ガラスエフェクトの応用とスコアボーナス

投稿記事 by SAI » 13年前

あけましておめでとうございます。今年もよろしくお願いしますm(_ _)m
別に元日に年賀状が一枚も届かなかったからって泣いてなんかいません。



やっとこさ次の動画ができあがったので生温かい目で見てやってください。
ついにナムアニクラウドさんに教えていただいた黄金角の出番がやってきました。
見栄えがものすごくいいですね。しかも応用が利くので様々なところで使っていきたいです。
[nico]http://www.nicovideo.jp/watch/sm16589731[/nico]

今回は本格的に道中を作り始めた、というところです。
時間がかかったところは、やはり目に見えない、「いかに楽に中身を作る環境を整えるか」というところです。
今回の場合なら、敵の出現がそれにあたります。
最初は敵1体出すのに5行ほど必要でしたが、いくらなんでもこれはヒドイということで色々考え、どうにか1行に収めることに成功しました。
ちなみに龍神録のようにcsvファイルを作って読みこむことはしません。
csvファイルだと編集した内容を適用するのにいちいちファイルを閉じないといけないからですし、
第一にファイルを作って読みこむ必要がないからです。
csvを使うことの利点は、エクセルなのでパッと見、数字の持つ意味が理解しやすいことにあると思います。
でもVCなら引数リストが見れるのでそんな必要はありません。
また、メモ帳を使ってそれを読み込む場合の利点としては、数字を変更した際にいちいちゲームを起動し直さなくていいということが挙げられますが、
VCでも同様のことができるので起動し直す必要がありません。(たくさんインクルードされてるヘッダファイルを変更するのは厳しいですが)

そんなわけで敵の出現パターンは直接コードに書いてるのですが、実際のところどうなのでしょうか?
一人でゲームを作る分にはこれでいいと思うのですが、ファイル読み込みには他にもメリットがあるのでしょうか?


ここからはプログラムしたことに対してあーだこーだ言ってます。

リザルト画面を作りました。最初の文字が出るところは龍神録っぽくしてみました。
そしてずっとやりたかったスコアボーナス。
TOAのグレードやスマブラDX(スマデラと呼ぶ自分は少数派なのか?)の評価制乱闘の発想で作りました。
これのまた時間のかかることかかること。
ちなみにボーナス数は今のところ138個です。大台突入。もう思いつかない。
何か考えていただけたら、実装が大変などの理由がない限り採用させていただきます。
本当はもっと欲しいんですよね。でもSTGだと強制スクロールだったり攻撃の種類が少なかったりでやることに制限があるのであんまり数が出ないというか。でもすでに結構出てる気がするというか。
ちなみにボーナス一覧はこちらです。
メモ帳だとインデントが揃ってるのに・・・(´・ω・`)
► スポイラーを表示
バグが色んなところに潜んでそうで怖いです。
アイテム全回収とアイテムを取らないのボーナスが両方とれておかしいなあ。
なんてことがあったので、ボーナス関係は要注意ですね。バグがあっても致命的ではありませんが・・・。
怖いのはもっと根本的な奴です。リプレイとか。

装備の仕様を大幅変更しました。
今までは、プレイヤーが持つショットの種類の情報は、「持ってる全装備の上から何番目か」というint型を持たせていました。
これだと全装備を並べ替える処理が大変になりそうなので、「別にプレイヤーに装備のデータ(Cequip型)持たせればよくね?」
となって変更することにしましたが、変更場所の多いこと多いこと。
やはり仕様変更は早めにやっとかないといけませんね。


今回3Dにまた一歩足を踏み入れました。ゲーム中ではアレキサンドライトの欠片として登場したアイテムです。
これは全面的に3Dで描画しています。(宝石と回ってる白いの)
今までの3Dは、2Dの画像を3D空間に描画するものですが、今回厚みのあるものに挑戦しました。
よくよく考えてみれば、3Dモデルだって2D画像の集まりなんですよね。
そんなわけで、あの宝石は3角形の集合で立体的に見せています。
これが苦労したのなんの。VERTEX3D型の変数、VECTOR normとCOLOR_U8 difとCOLOR_U8 spcの意味が全然わからんし、
他にもライトとかカメラとか意味不明な言語が飛び交ってて、調べながらコードをいじって試行錯誤していました。
そしてnormが光を反射する方向のようなものを意味していて、今までこれが全てのポリゴンで同じ値だったため、うまくいかなかったことがわかりました。
なるほど、こいつをいじればいいのか。というわけで3頂点の重心を出して、宝石の中心座標とのベクトルの差を取ればそれっぽくなるんじゃないの?

なりました。ヽ( ´¬`)ノ ワ~イ

しかしここで次の問題が。
光が当たらないところは真っ暗になって何も見えなくなってしまうのです。
ここでまた試行錯誤して突き止めたのがエミッシブカラーです。
こいつは自己発光色を設定できるらしいです。
光が当たってないと見えるのはおかしいですが、ゲーム中では見えないと困ります。発光させちまいましょう。
(アイテムはゲーム中で真っ暗でも見えるのが当然なので周囲の反射光を自己発光に置き換えただけです)
そんなわけで光が当たってない部分も無事見えて、あんな感じになりました。
これを応用すればいろいろなものが作れるんじゃないか・・・?
3Dにだんだん興味が湧いてきました。
いずれ3D弾幕も作るのではと思います。(一口に3Dと言っても色々ありますが)


次はお金どうしよう。

なんのことかというと、敵を倒した時に落とすお金です。
敵を出現させるときにいちいち金額を設定するなんてめんどくさくてありゃしないので、モンスター図鑑からデータをもらうことにします。
あ、ちなみにHPもモンスター固有の値です。
しかし、みんながバラバラとお金を落としては、画面がお金で埋め尽くされてしまいます。これは困ります。紛らわしいです。
そんなわけでよく出る敵の場合はキリのいい金額を落として数を減らすことにしました。
(1G,5G,10G,100G,1000G,10000Gとあるので、1~2枚で済むように金額を調整)


まだあります。
処理落ちがー処理落ちがぁーーー・・・・orz
ここにきて無視できないレベルになってきました。
なにがいけないかはわかっています。
ソートです。
stable_sort()で弾の描画順を入れ替えているのが原因です。こいつが重い。
で、この関数を呼ぶ条件なのですが、「敵が弾を撃ったフレーム」に1度呼ばれます。
つまり、たくさんの弾を同じフレームに大量に出す時よりも、毎フレームちびちびと出す時の方が処理が重くなるんです。
これは当然といえば当然です。例えば60Fに1回ソートするとした場合、60Fおきに弾の見え方が前後することがあるからです。
(stable_sortなので、一度ソートされたもの同士では前後しないはずですが)
ですので理想としては弾を撃ったフレームにソートできるのが望ましいです。でも重い。どうしよう。
しかしこうなっては5Fに1回などの条件を追加しなければいけないかもしれません。
5Fくらいならバレないかなぁ・・・?
弾を発射した瞬間は発射エフェクトで弾が見えないのでとりあえず前のソートから5F経ってない場合は5F待ってソートすることにします。


最後に、リプレイにスロー再生をつけてみたが果たして誰得なのだろうか。

・・・俺得なのは間違いない。
プレイヤーや弾の動きを検証したりするのに役立ちそうですね。

長々と読んでいただいてありがとうございます。
ゲームの仕様のアイデアはとにかくたくさんの意見が欲しいので何か思ったことがあれば教えていただければ幸いです。
ではでは。

ちなみに毎年恒例の高尾山おみくじは吉でした。
・・・普通だなー。

アバター
ナムアニクラウド
記事: 16
登録日時: 14年前

RE: ガラスエフェクトの応用とスコアボーナス

投稿記事 by ナムアニクラウド » 13年前

>stable_sort()で弾の描画順を入れ替えているのが原因です。こいつが重い。
 弾のソートって本当に必要ですか?自分の場合はやってませんが・・・
SAIさんが以前弾の描画順で困っていたことは知っているんですが、具体的にどんな問題だったかわからなくなってしまったので、よろしければ弾をソートする理由について詳しくお願いします。

>ついにナムアニクラウドさんに教えていただいた黄金角の出番がやってきました。
 使ってくれてありがとうございます(;ω;)
自分でも使ってみて思ったのですが、なかなか思い通りの見た目になってくれませんね。
黄金弾幕を自由に操れるようにもう少し研究していく所存です。

>ちなみにボーナス数は今のところ138個です。大台突入。もう思いつかない。
>何か考えていただけたら、実装が大変などの理由がない限り採用させていただきます。
 他のSTGの名前を取ったパロディとかどうでしょう?被るのもあるけど・・・
 「斑鳩なチェンジ」・・・片方のキャラの使用率が45~55%
 「サイヴァリア張りのグレイズ」・・・グレイズが多い
 「東方張りのスペルゲット」・・・スペルをすべて取る
 無理がありますね(自分は東方しかプレイしてないし)。

>そんなわけで敵の出現パターンは直接コードに書いてるのですが、実際のところどうなのでしょうか?
 C#なので参考にならないと思いますが、自分の場合はイテレータブロックという機能を使って、少し邪道ですが、次のように書いています。

CODE:

//関数定義とかいろいろ省いてます
//イテレータブロック。「yield return null」で処理を一旦抜け、後で再開できる。
public static IEnumerator Sequence1()
{
	for( int j = 0; j < 20; j++ )
	{
		//Create( 敵リクエスト(enum), 初期座標, スピード倍率, 左右反転フラグ );
		Create( Request.Enemy1, new Vector2D( 50, 0 ), 1.0, true );
		for( int i = 0; i < 80; i++ ) yield return null;	//80F待つ
	}
	//ブロックを抜けると、あるフラグが立ってステージクリアとなる
}
 いわゆるマイクロスレッドです(東方弾幕風でも採用している)。
敵の行動の制御や、弾の動きの制御、エフェクトの動作などにも使えて便利です。
そのうち"Roslyn"がリリースされたらこの部分をスクリプトとして書くことができるので、C#にはかなり期待してます。

SAIさん頑張ってください。自分も頑張るぞ!

アバター
SAI
記事: 115
登録日時: 14年前
住所: はひほーひ

RE: ガラスエフェクトの応用とスコアボーナス

投稿記事 by SAI » 13年前

ナムアニクラウドさんいつもありがとうございます!

>弾のソートについて
主に2つの理由で行っています。一つは、大きな弾が小さな弾の上に描画されてしまうと、小さな弾が見えなくなってしまうので大きな弾から描画する必要があります。
もう一つは、見栄えの問題です。弾をソートせずに描画すると、弾が重なったときに見栄えが悪くなります。例えば龍神録の「混沌と螺旋」では、新しく出現した弾は必ず一番上に見えるように描画されているため、螺旋を描いて見えます。しかしソートせずに描画順がめちゃくちゃになってしまうとあっちこっちで一番上に見える弾が出てきてしまい、螺旋に見えなくなってしまいます。
(描画順がめちゃくちゃになる原因は、新しく弾を撃つときに配列の空いてるところを探す際、先頭から探していることにあります。)
これらの問題からソートをすることにしています。

>他のSTGのパロディ
STGに限らず自分の好きなネタは取りいれていきたいですが、STGは東方以外全然やったことないのです・・・(´・ω・`)
でも戦闘時間が45%~55%というのはいいですね! 結構戦闘中はチェンジを忘れて片方に偏りがちだと思うので。
名前は、うーん、斑鳩はやったことないので無難に「共闘」とかにしましょうか・・・・。

>マイクロスレッド
おお、確か遥か昔に弾幕風で一度勉強しましたよ。
でも上から下に行くのに慣れてたので読んでもさっぱりでしたw
特にメリットが感じられず、あまり魅力的に感じませんでした。

ちなみに今回動画にした道中のコードはこんな感じです。

CODE:

void event_boss1_EASY(int flag)
{
	if(flag==0)//ここはスルーで
	{
		//group関数の引数は、前から出現し始めの時間、出現し終わりの時間、出現間隔を表し、この場合10Fに一回200Fにわたって敵が出されてる
		//次に座標、敵の種類、攻撃倍率、行動パターン(およびその行動パターンに必要なパラメータ)、
		//ショットパターン(およびそのショットパターンに必要なパラメータ)、アイテムの種類とその数 
		//enemy関数は時間関係の引数が1つになり、その時間に1体だけ出現させる

		group(200,400,10,EMINX,150-GetRand(100),Ssraim,atkrateE,move.getp(VL,7+Drand(-2,2)),shot.getp(RWK20,40+GetRand(30),500,Red,0,100),item.getp(Power_S,1));
		group(500,700,10,EMAXX,150-GetRand(100),Ssraim,atkrateE,move.getp(VR,7+Drand(-2,2)),shot.getp(RWK20,40+GetRand(30),500,Blue,0,100),item.getp(Power_S,1));


		enemy(900,HFX,EMINY,Imash,atkrateE,move.getp(HandAU,10,700),shot.getp(roseH,50,600),item.getp(Power_M,1,Score_S,2));

		enemy(1500,HFX-100,EMINY,Imash,atkrateE,move.getp(HandAU,10,700),shot.getp(roseH,50,600),item.getp(Power_M,1,Score_S,2));
		enemy(1500,HFX+100,EMINY,Imash,atkrateE,move.getp(HandAU,10,700),shot.getp(roseH,50,600),item.getp(Power_M,1,Score_S,2));
		group(1506,1606,20,EMINX,150-GetRand(100),Fspirit,atkrateE,move.getp(Naname,4,0,PI/12),shot.getp(PB3,40+GetRand(30),150,Red,5,10+GetRand(3)),item.getp(Power_S,1));
		group(1500,1600,20,EMAXX,150-GetRand(100),Ispirit,atkrateE,move.getp(Naname,4,0,-PI/12+PI),shot.getp(PB3,40+GetRand(30),150,Blue,5,10+GetRand(3)),item.getp(Score_S,1));

		enemy(2300,HFX,EMINY,forestmash,atkrateE,move.getp(HandAU,10,1600),shot.getp(flowerH,100,1500),item.getp(Alexandrite,1));

		if(STGevent.gettime()==4500)	//終了
		{
			result.start();
		}
    }
}


アバター
bitter_fox
記事: 607
登録日時: 14年前

RE: ガラスエフェクトの応用とスコアボーナス

投稿記事 by bitter_fox » 13年前

SAI さんが書きました:>弾のソートについて
主に2つの理由で行っています。一つは、大きな弾が小さな弾の上に描画されてしまうと、小さな弾が見えなくなってしまうので大きな弾から描画する必要があります。
もう一つは、見栄えの問題です。弾をソートせずに描画すると、弾が重なったときに見栄えが悪くなります。例えば龍神録の「混沌と螺旋」では、新しく出現した弾は必ず一番上に見えるように描画されているため、螺旋を描いて見えます。しかしソートせずに描画順がめちゃくちゃになってしまうとあっちこっちで一番上に見える弾が出てきてしまい、螺旋に見えなくなってしまいます。
(描画順がめちゃくちゃになる原因は、新しく弾を撃つときに配列の空いてるところを探す際、先頭から探していることにあります。)
これらの問題からソートをすることにしています。
それなら弾発射時に挿入位置を調節して、常にソートされている状態にしたらいかがでしょう?
ただ配列だと結構な要素をずらさないといけないんで面倒くさいし、重くなりそうですが・・・

アバター
SAI
記事: 115
登録日時: 14年前
住所: はひほーひ

Re: ガラスエフェクトの応用とスコアボーナス

投稿記事 by SAI » 13年前

なるほど、そういうやり方もあるんですね!
ただこのやり方の場合は撃った弾の数で処理の重さが決まるので実際に作ってみて処理時間を比べないといけませんね。
あと消滅したときは、そこを切り詰めないといずれ配列がパンクしてしまいますね。
実装が大変そうなので再び処理落ちに困ったら試してみたいと思います。
アドバイスありがとうございました!

アバター
bitter_fox
記事: 607
登録日時: 14年前

Re: ガラスエフェクトの応用とスコアボーナス

投稿記事 by bitter_fox » 13年前

SAI さんが書きました:なるほど、そういうやり方もあるんですね!
ただこのやり方の場合は撃った弾の数で処理の重さが決まるので実際に作ってみて処理時間を比べないといけませんね。
あと消滅したときは、そこを切り詰めないといずれ配列がパンクしてしまいますね。
実装が大変そうなので再び処理落ちに困ったら試してみたいと思います。
アドバイスありがとうございました!
リスト構造を使うと楽だったり早そうですね。