HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2011
1010
顔芸弾幕シューティングについて15解決


顔芸

リンク

2011/10/10(Mon) 16:05:14|NO.42212

はじめまして。
hspを初めて1年半の者です。自分で調べても解決には至らなかったので苦肉の策で投稿させて頂きます。


早速本題ですが、自分は今HSP ver3.21を使って弾幕縦スクロールシューティングゲームを作っているのですが、
弾幕STGを作るにあたって最も処理の負担が大きい部分はどこでしょうか?
また、それが各々のスクリプトによって異なるならば、どのような記述を避けるべきでしょうか?

漠然とした質問で申し訳ありませんがどなたかお答えして頂ければ幸いです。


<以下補足>
初めはHSP標準の命令で作っていたのですが、画面に弾が100発も描画されないくらいで処理落ちが起こり、話にならない状況でした。
そこでDirectXを用いて作り直したところ、多少は改善したのですがそれでも100〜200発で再び処理落ちが発生してしまい、
スクリプトの見直しを痛感した次第です。他所で数千発の弾を管理できているのを目にしたため目標は1000発程度です。



この記事に返信する


ひらまる

リンク

2011/10/10(Mon) 16:36:57|NO.42217

>最も処理の負担が大きい部分はどこでしょうか?
最も非効率な処理をしている部分です。

私の場合は「重いな」と感じたら、1つずつ機能をコメントアウトしていって、
「この機能をなくしたらFPSが一気に上がったな…この周囲を改良するか…」って感じで速度向上を図っています。
どこが重くなるかは人によってまちまちなので、ソースを見ないとなんとも言えません。
100発程度で重くなるのは確かにどこかに問題があるのでしょう。
HSP製で1000発以上の弾がでるシューティングゲームは私もプレイしたことがありますが、かなり快適でした。
もしかしたらパソコンのスペックの問題かもしれないので、プレイ動画だけでなく自分でプレイして確かめる必要もあるかもしれません。



ORZ

リンク

2011/10/10(Mon) 16:57:23|NO.42218

具体的にどのような処理をしているのか全く書かれていないので一般的な事しか言えないのだが
プログラミングにはパレートの法則が当てはまる。一般的には描画処理が全体の殆どを持っていく重たい処理だ。

HSPに限った話だと、ループ内で画像の読み込みや、変数の定義などをすると減速の要因になる。
特にddimやsdimなどの命令はゲームが始まる前にやっておき、メインループ中では一度も出てこない事が望ましい。
さらに、配列を自動で拡張するなどの処理も入れられないようにしなければならない。
文字列型変数と数値型変数を行き来するような変数は大問題だ。文字列型変数は64文字まではセーフのはずだが
それを越えると領域が自動で拡張され、その際にパワーを消費する。
またモジュール変数への命令や関数を介したアクセスは目ン玉飛び出るほど遅いのでやらない事が望ましい。



顔芸

リンク

2011/10/10(Mon) 17:11:12|NO.42222

>ひらまるさん ありがとうございます。やはり100発はおかしいですよね; 弾幕STGはプレイしますしいろいろと参考にしていますが問題なく動作します。

>ORZさん ご返答ありがとうございます。具体的なアドバイスもありがとうございます。
まだまだ勉強不足で、変数の型などは理解が浅いです;おっしゃるとおりならやはりnoteget→strで変換もまずいですかね;;



顔芸

リンク

2011/10/10(Mon) 17:15:44|NO.42223

ご返答ありがとうございます。FPSはチェックしていませんでした;地道にチェックしていくことにします。
記述に無駄が多そうなのは敵機と敵弾の処理の辺りだろうかと思い載せてみました。

<略>

*enemyset if flame\10=0 { es_new en,point_1 noteget entype,noteline entype.en=str(entype) ;notegetで出現パターン読み込み。テキスト中0か空白は待機。notegetは文字型変数で受け取るのでstrで数値に変換。 noteline+=1 if entype.en!0 { if entype.en=1 :enhp.en=5:chno.en=81 ;chno:キャラクターナンバー if entype.en=2 :enhp.en=7:chno.en=82 ;発生する敵の種類分岐(今は三択) if entype.en=3 :enhp.en=1:chno.en=83 if entype.en=1000 :noteline=0 ;読み込み文末は1000 endir.en=0 ex=rnd(370) es_set en,ex,-enys+15,chno.en,,1 es_type en,4 } } gosub *enemymove_hit_shot <略> *enemymove_hit_shot en=0 repeat point_2-point_1 es_find en,4,en,point_2 if en=-1 :break switch entype.en case 1 if flame\3=0 :endir.en+=1 es_adir en,endir.en,200 es_get eny,en,5 if eny>=50 :gosub *enshotcase_1 swbreak case 2 es_adir en,0,400 es_get eny,en,5 if eny>=50 :gosub *enshotcase_2 swbreak case 3 es_adir en,0,800 es_get eny,en,5 if eny<=200 :gosub *enshotcase_3 swbreak swend ;hitcheck ;own-enemy es_check hitown_enemy,1,,,en,en if hitown_enemy=en { es_kill en mmplay 0 } ;ownbullet-enemy es_check hitownbullet,en,2,,2,point_1 if hitownbullet!-1 { es_kill hitownbullet enhp.en-=1 if enhp.en=0 { es_kill en mmplay 0 } } en+=1 loop ;own-enemybullet enemybullet=0 repeat es_find enemybullet,8,enemybullet if enemybullet=-1 :break es_check hitenb,1,8,point_3 if hitenb!-1 { es_kill hitenb mmplay 0 } enemybullet+=1 loop return *enshotcase_1 if flame\10=0 { es_new enb,point_2 es_set enb,enx.en+16,eny.en+16,kpl+kob+ken+1+29 es_type enb,8 es_get enx.en,en,3 es_get eny.en,en,5 enbdir.en+=30 es_adir enb,-enbdir.en,200 es_effect enb,32,32,0,0,enbdir.en } return *enshotcase_2 count.en+=1 if count.en=1 :es_get enx.en,en,3:es_get eny.en,en,5 if count.en>=1&count.en<=100 { es_new enb,point_2 es_set enb,enx.en+16,eny.en+16,kpl+kob+ken+1+15 es_type enb,8 enbdir.en+=20 if enbdir.en>=360 :enbdir.en=0 es_adir enb,enbdir.en,300 es_effect enb,32,32,0,0,enbdir.en if count.en=100 :count.en=-100 } return *enshotcase_3 bulkind=rnd(8) buldir=rnd(360) es_new enb,point_2 es_set enb,enx.en+16,eny.en+16,kpl+kob+ken+1+32+bulkind es_type enb,8 es_get enx.en,en,3 es_get eny.en,en,5 es_adir enb,buldir,200 es_effect enb,32,32,0,0,buldir return
長たらしくすみません。

*enemysetはメインループ内で以降サブルーチンです。敵機の動きは適当に試作したので変数管理が雑です;
gosubのネスト構造はまずいですかね?;あと気になるのは、敵機をシナリオ(?)通りに発生させるためにnotegetで
テキストファイルから読み込んだ数字でswitch分岐につなげているところです。
なにかアドバイス頂けないでしょうか。よろしくお願いします。



顔芸

リンク

2011/10/12(Wed) 18:48:20|NO.42304

解決しました。
当たり判定の部分を削除したところ一気に処理速度が改善しました。
es_checkって重いんですかね。。。?

掲示板でのマナーをわきまえておらず、見にくいスクリプトを貼ってしまい申し訳ありませんでした;以後気をつけます。
回答して下さった方、ありがとうございました。



ひらまる

リンク

2011/10/12(Wed) 19:10:44|NO.42305

es_checkが重いー?
hspdxfixあんま使ったことないけど、dllの当たり判定は高速そうなイメージだけどなぁ。
es_checkが重いというか、es_checkを無駄にループで何度も呼び出してるから重い可能性もあるんでね?
上のスクリプト読んでないからなんとも言えないけどね。



check

リンク

2011/10/12(Wed) 19:20:01|NO.42306

画面を5回更新する間に1回あたり判定を行うとかの処理に書き変えてみたらどうだ。



てれてれ

リンク

2011/10/12(Wed) 19:34:29|NO.42307

顔芸さんはes_checkのp5,p6を省略してるようですが、
es_checkのp5,p6の検索範囲を指定して、
検索する必要の無いスプライトNoの検索を回避することで改善されるかと思います。



顔芸

リンク

2011/10/12(Wed) 23:18:40|NO.42318

みなさんご意見ありがとうございます。

>てれてれさん その点はes_checkに気づく前の苦悩の時期に改良しました(笑
es_findとes_getを使って出した二点間の距離を用いたヒットチェックを試したところ、
当初の目標であった1000発は普通に超えました。でもひらまるさんやcheckさんの
アドバイスが気になっておおざっぱですが実験してみました。

内容は、とりあえず随時FPSを書き出せるようにして、まったり動く敵からもっさり弾を
発射してもらって、FPSが50を切ったらボム(弾・敵消し)を自動入力して、消えた
スクリプトの数を書き出すというものです。

上記のヒットチェックだと2772発消してました。
アドバイス頂いた通り5フレーム毎の判定にすると3179発に増えましたw
で、以前のes_checkバージョン+5フレーム作戦でいくと1207発でした;;

他言語について他所で似たようなチェック命令が遅いという記述を見てまさか・・
とおもったわけですがやっぱり遅いのかな?;
まぁ簡単な実験なんで断定はできませんが

またもや長文ですみません;



ひらまる

リンク

2011/10/13(Thu) 00:34:17|NO.42322

そこまでしっかり調べたのなら大丈夫でしょう。
多分es_checkが遅いです(・ω・)
というより円形(距離)の判定が速いですね。
元々2772出せるのなら、5フレーム毎にして3179はコスパ悪いですね。
精度も落ちるので1フレーム毎に調べた方が良いと思います。
あとは「自機に絶対当たらない弾」を発射時に判定して、
1フレーム毎の判定から外せるともっと速くなるかもしれません。
いや…これこそ5フレームとか10フレーム毎に判定した方が…?
まぁ変なテクニックを詰め込み過ぎてもバグのもとなので、
現状1000発以上撃てるなら良いのではないでしょうか。
(画像のサイズが大きくなると一気に速度が落ちる場合もあるから注意)



顔芸

リンク

2011/10/13(Thu) 00:46:36|NO.42323

>ひらまるさん
ありがとうございます。

たしかに5フレーム毎にしたから単純に5倍近く速くなったりして・・とか
淡い期待を抱きましたがさすがにそれは甘かったですw
自分のスクリプトが悪くて全体の速度があんま上がってない可能性も十分あるでしょうから
ひとまずはこれ以上探らず、円の判定でいこう っていう結論に留めておきます。

絶対に当たらない弾・・画像サイズ・・
気になって先に進めない(笑

本当に再三のアドバイスありがとうございますm(_ _)m



暇人

リンク

2011/10/13(Thu) 06:23:24|NO.42326

多分使い方間違ってない?
一度に判定する数が多いほどスクリプトで判定するよりes_checkのが速くなる
1000以上なら数十倍速いと思う

付属のhspdxサンプルをいじったものだけど

#include "hspdx.as" wx=640:wy=480 es_ini 10000 ; system初期化 es_screen wx,wy,32,,1,1 ; スクリーン初期化 if stat=1 : goto *dderr1 if stat=2 : goto *dderr2 goto *start ; 正常に完了 *dderr1 dialog {"DirectXの初期化に失敗しました。 "},1 end *dderr2 dialog {"スクリーンの初期化に失敗しました。 "},1 end *dderr3 es_bye wait 100 dialog {"VRAMの容量が不足しています。 "},1 end ;------------------------------------------------------------------ *start chrsx=64:chrsy=64 ; キャラクタのサイズを指定 buffer 3 picload dir_exe+"\\sample\\hspdx\\testchr.bmp" es_buffer 0,2 if stat : goto *dderr3 es_size 64,64,100 es_pat 0, 0,64 es_area -64,-64,wx,wy ; 画面ボーダー設定 gsel 0,1 es_cls es_sync wait 100 es_set 0,250,250,0 ;自機 es_type 0,1 max=2000 ;2000発設定 dim hids,max repeat max,1 ;弾No1から a=rnd(64):spd=rnd(10)*25+250 x=rnd(640):y=rnd(480) es_set cnt,x,y,0 es_adir cnt,a,spd es_flag cnt,$6200 ; X,Yバウンド設定 es_type cnt,2 loop *gmain mcnt+ es_cls stick ky,$1f ; キーの情報を取得 if ky&$e0 : goto *owari ; [ESC]中断チェック n=0 repeat max,1 es_check hid,0,2,0,cnt,max+1 if hid>0{hids(n)=hid:n+ : continue hid+1};当たった弾のIDを溜めてIDに+1してloop loop es_draw pos 0,0:es_mes "ヒット数="+n+" CPU使用率="+tttt+"%" es_timer t,0 es_sync 16 ; 1/60? es_timer tt,0 ;es_syncのstatがうまく機能して無い感じだからes_timerで代用 ttt+tt-t if (mcnt\60)=0 { tttt=(1000-ttt)/10:ttt=0 } await 0 goto *gmain *owari es_bye end



顔芸

リンク

2011/10/13(Thu) 14:53:21|NO.42334

>暇人さん
ありがとうございます。

なるほど、CPU使用率なる指標もありましたね。たしかにこのスクリプトだとes_checkでも
1000発余裕ですね;使用率67%程度でしたし。同じようにFPS調べても65程度と安定
していました。

でも2000発だとFPSが55、2700発で40前後になりましたが、同時に判定する数
が多いとes_checkが有利というのはどういった理由からなのでしょうか?
自分にはes_checkが中で何をしてくれているのかさっぱりわからないものでw;



暇人

リンク

2011/10/13(Thu) 21:00:11|NO.42349

弾の移動をhspdxに任せてるのに1000発で使用率60%超えてるって事は描画に時間かかってるかな?
es_drawの前後の時間とes_checkのあるループがどれぐらい時間かかってるか個別に計ってみれば良いかも
多分1000発判定しても1msいくかどうか(自分の環境では5000発でも0か1ms)

es_drawに時間が取られてるならes_sizeを16,16とかにしたら少しは改善するかもしれない
グラボ使ってる場合ほとんど変らないが・・・

後、載せたスクリプトに間違いがあった

if hid>0{hids(n)=hid:n+ : continue hid+1};当たった弾のIDを溜めてIDに+1してloop
ヒットしない残り弾数分リピートしてた

if hid>0{hids(n)=hid:n+ : continue hid+1}else{break};当たった弾のIDを溜めてIDに+1してloop
当たらなかったらループを抜ける


>同時に判定する数 が多いとes_checkが有利というのはどういった理由からなのでしょうか?
たんに当たったかどうかのチェックだけなら数に関係なくes_checkのが早い
ただ一個判定するのに1の時間がかかるが一度に100個判定しても1.1ぐらいの時間しかかからない感じ
スクリプトの場合100個の判定には1個にかかる100倍の時間が掛かる(実際には違うけど)



顔芸

リンク

2011/10/13(Thu) 22:18:24|NO.42351

>暇人さん
5000ですか!環境でそんなに違うもんなんですね;;PCの性能も悪いのかなぁ;
es_checkが数に関係ないというのはそういうもんだと思っておきます^^;

また検証してみたいと思いますがとりあえず判定領域が円形のほうが勝手がよかったので
今回はそういう意味でも円形でいかせて頂きますね。

丁寧なご返答ありがとうございました。また機会があればよろしくお願い致しますm(_ _)m



ONION software Copyright 1997-2023(c) All rights reserved.