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


HSPTV!掲示板


未解決 解決 停止 削除要請

2014
1230
墨鴉HSP3Dishだけで擬似3Dをやりたい10解決


墨鴉

リンク

2014/12/30(Tue) 18:51:44|NO.66725

はじめまして。

マルチプラットフォームに対応できるようにHSP3Dishを使って「ファイナルファイト」や
「天地を喰らう」のようなベルトスクロールアクションゲームを作りたいと考えています。

そのためにはキャラクターの描画順の概念(3DではZ軸というのでしょうか?)が必要になると
思うのですが、これの上手い考え方がわかりません。

現状のアイディアでは、キャラクターのデータが収まっている配列100個に順番にアクセスする
方法しか思いつかないのですが、これでは確実に重くなってカクカクになり動かなくなると
思います。

キャラクターのZ軸を管理している配列をソートという処理を行って並べ替えるといいらしいと
聞いたのですが、ソートというものはHSPではHSPDAというDLLを使うのが一般的らしく、
それではHSP3Dishでは使えません。

どなたかよい解決方法をお教えください。



この記事に返信する


cats

リンク

2014/12/30(Tue) 18:59:49|NO.66726

3DをAndroid、iOS端末で動かすモジュールはいくつかあります。
最も有名なのはd3moduleでしょう。基本的な図形が描画できます。
また、今年のコンテストで新しい3dモジュールが公開されました。
http://dev.onionsoft.net/seed/info.ax?id=843
こちらの方が高機能です。(キャラ描画に向いているかは分かりません。)
>ソートというものはHSPではHSPDAというDLLを使うのが一般的らしく
3DのZソートと、クイックソートなどは別物です。
3Dモジュールを自分で作りたいなら線形代数の知識が必須です。
高速化には難しいアルゴリズムに挑戦することになります。
既存のモジュールを使用するのが無難かと思われます。



墨鴉

リンク

2014/12/30(Tue) 19:10:59|NO.66728

cats様

レスありがとうございます。

d3moduleなどの擬似3D関係のモジュールの存在は把握していたのですが、
あまりにも難しく、キャラクターの重ね合わせのためだけに導入は難しいと思っていました。

クイックソートなどを行ってくれるモジュールの自作も難しいのは承知なのですが、
わたしの調べ方が悪いのか、いいモジュールを公開しているサイトが見付かりません。
もしよいソートモジュールをご存知でしたらお教えいただけると助かります。



cats

リンク

2014/12/30(Tue) 19:42:54|NO.66729

> 墨鴉 さん
d3moduleはzソートもなく、キャラクター描画には向いていないでしょう。
HU3DMの方はzソートが可能でモデルの専用ファイルもあります。
ただし、かなり難しいです。

>もしよいソートモジュールをご存知でしたらお教えいただけると助かります。
先ほども書きましたが、私の知る限りでは3Dで使うZソートとクイックソート、バブルソート系は全くの別物だと思います。
Zソートについて。
http://sola.eee-craft.com/sola5/tips/zsort.html



zakki

リンク

2014/12/30(Tue) 19:56:07|NO.66730

ファイナルファイトのような2Dキャラクター&奥行き移動のゲームだと
奥行きは限られた範囲の整数(たとえば0〜31)で足りませんか?

一般的な3DゲームをZソートで描画するには実数のZ値を持つ多数のポリゴン同士の前後判定が必要で
高速に動作させるには複雑なアルゴリズムが必要になりますが
そうでなければバケットソートが高速ですし自作も簡単です。

ここの_baqetsortのようなことをキャラクターデータの持ち方にあわせて実装するとよさそう。
http://wiki.hsp.moe/%E9%85%8D%E5%88%97%E6%93%8D%E4%BD%9C%E7%B3%BB%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB.html



墨鴉

リンク

2014/12/31(Wed) 10:21:46|NO.66737

>>cats様

仰るとおり、標準命令だけで3Dが扱えるということでHU3DMは触れてみましたが、d3moduleよりも
更に難解で愕然としましたし、キャラクターを奥行きに従って並べたいという以外は
事実上2Dゲームなので不要な機能が多すぎました。

zソートに関してはわたしは標準命令で原始的なアルゴリズムのゲームを作るのが精一杯の
技術力しかなく、理解不足で説明が上手くできず申し訳ありません。

>>zakki様

クイックソートなどの言葉は聞いたことがありましたが、「バケットソート」というのは
初めて聞きました。
調べてみましたら、わたしでもかろうじて理解できてしかも動作も速いらしいので、
これで試してみようと思います。



cats

リンク

2014/12/31(Wed) 10:46:18|NO.66738

NO.66725で挙げられていたゲームを調べてみましたが、これは3Dは必要ありませんね。
3Dエンジンを使っていると思われるゲームもありますが、簡単なものは使っていなさそうです。
これは視点が固定なのでZソートは要らないと思います。
後ろにあるものから順番に描画していけば済みます。
Z軸でどの位置にいるかをキャラクタ分の配列変数に保存させておけばいいです。
こういったゲームはやったことが無いので、見当違いでしたらすいません。



リンク

2014/12/31(Wed) 11:00:44|NO.66739

作りかけのDISH用擬似3Dスプライトモジュールから、でかすぎるので
必要最小限の切り貼りソースですみませんがこんな感じ。
ファイナルファイトタイプならY座標の比較ソートで十分でしょう。
透明色がうまくいってませんが1行目コメントアウトすればwin版では有効に。
png画像使えばgmode3でdish版でも透明色使えます。

#include "hsp3dish.as" #define SP_MAX 256 #module #deffunc eds_init int _p1 ,int _p2 ,int _p3 //初期化 max=_p1 ;スプライト最大数 dim spFlg,max ;スプライト存在フラグ dim spChr,max ;スプライトパターン dim bufNo,max ;所属バッファ ddim hitSize,max ;ヒットサイズ ddim spX,max ;スプライトX座標 ddim spY,max ;スプライトY座標 ddim moveX,max ;オート移動X ddim moveY,max ;オート移動Y ddim ar2,max ;ソート用一時バッファ ddim drawOrder,max ;描画オーダー dim bufPartX,8:dim bufPartY,8 ;バッファ毎のスプライトサイズ保存(とりあえず8) zoomReg=_p3 ;標準ズーム倍率 rotDiv=_p2 ;周の分割数 rotRad=M_PI*2/_p2 ;1分割あたりのラジアン値 return //バッファの初期化 バッファID、x分割、y分割、基本座標 #deffunc eds_init_pat int id, int _p1, int _p2, int _p3 spBuf=id bufPartX.id=_p1:bufPartY.id=_p2 celdiv spBuf,_p1,_p2,_p1/2*limit(_p3,0,1),_p2/2*_p3 return //新規スプライトをセット #deffunc eds_set int id, double _p1, double _p2, int _p3 ,int _p4 spFlg.id=1 spX.id=_p1 spY.id=_p2 spChr.id=_p3 bufNo.id=spBuf return #deffunc eds_calc //アニメ、オート移動計算 repeat max if spFlg.cnt==0:continue num=cnt spX.num+=moveX.num spY.num+=moveY.num loop return #deffunc eds_adir int id, int _p1,int _p2 //オート移動セットdir moveX.id=sin(rotRad*_p1)*_p2/100 moveY.id=-cos(rotRad*_p1)*_p2/100 return #defcfunc eds_newsp int _p1,int _p2 //未使用スプライトを返す関数 sp_no=-1 repeat _p2-_p1+1,_p1 if spFlg.cnt==0{sp_no=cnt:break} loop return sp_no #deffunc eds_draw //スプライト描画 edsZ_sort repeat max num=drawOrder.cnt if num!=-1{ pos spX.num,spY.num celput bufNo.num,spChr.num,zoomReg,zoomReg,0 } loop return #deffunc edsZ_sort //描画順ソート(Y座標比較) memcpy ar2,spY,max*8 ;spYを壊さないようコピー作る repeat max ;描画スプライト番号をつける。未使用は-1にしておく if spFlg.cnt==1{drawOrder.cnt=cnt} ; else:drawOrder.cnt=-1 loop repeat n=1<<cnt ; マージサイズ m=n*2 ; セグメント サイズ repeat p=m*cnt ; セグメント開始点 p1=p ; パート 1 開始点 e1=p1+n ; パート 1 終了点 p2=e1 ; パート 2 開始点 e2=limit(p2+n,0,max) ; パート 2 終了点 (clipping) s=e2-p1 ; セグメント サイズ if s<=n:break ; セグメント サイズが閾値以下なら マージしない repeat s if p2>=e2{ ; p2 領域外 tr.cnt==ar2.p1:tr2.cnt=drawOrder.p1:p1++ } else:if p1>=e1{ ; p1 領域外 tr.cnt==ar2.p2:tr2.cnt=drawOrder.p2:p2++ } else:if ar2.p1<ar2.p2{ ; 比較 & マージ ここ>か<で昇降変更★ tr.cnt==ar2.p1:tr2.cnt=drawOrder.p1:p1++ } else { tr.cnt==ar2.p2:tr2.cnt=drawOrder.p2:p2++ } loop memcpy ar2.p,tr,s*8 ;マージされた配列をコピー memcpy drawOrder.p,tr2,s*4 ;描画オーダーコピー loop if n>=max:break ;ソート 完了 loop return #global /////////////////////////////////////////////////////メイン(終了はXで) gmode 2 celload dirinfo (1)+"/sample/game/face.bmp",1 eds_init SP_MAX,64,1 ;スプライト初期化 eds_init_pat 1,64,64,1 ;バッファ初期化 repeat SP_MAX ;スプライトセット newsp=eds_newsp(0,SP_MAX-1) if newsp==-1:end eds_set newsp,rnd(320),rnd(480),0,100 eds_adir newsp,rnd(64),80+rnd(40) loop repeat redraw 0 color 0,0,0:boxf ;画面クリア eds_calc ;オート移動計算 eds_draw ;スプライト描画 await 16 redraw 1 loop



Drip

リンク

2014/12/31(Wed) 15:59:57|NO.66745

こんにちは。Dripです。
墨鴉さん、こんにちは。

バケツソートは実質的にはソート処理らしい処理は無いので滅茶苦茶高速で簡潔です。
一方最高の実行速度を得るには汎用モジュール化しにくい側面があるかもしれません。
徹底的に無駄を省く場合は自分なりに理解して組み込む必要があるかと思います。
下記はバケツソートをしながら敵キャラクターを描画するサンプルです。
キャラクタの動作部を含めて整形しても60数行なので参考にしてみてくださいね。

#include "hsp3dish.as" //DISH 対応 #define emax 100 //敵の最大数 (★注意:8bitで管理するので最大255人まで。それ以上必要なら要改造) #define lmax 200 //Y座標の最大(★注意:((emax+1)*lmax)バイトのメモリを食います) sdim sort,lmax,emax+1 //バケツ(最大Y座標個のバケツ×(最大敵人数+バケツあたりの敵の数カウンタ)) //sort(0)にY座標あたりの敵の数カウンタ、sort(1〜)に敵IDが格納される仕組みです。 dim ecol,emax //敵の色 ddim ex,emax :ddim ey,emax //敵のX,Y座標 ddim emx,emax :ddim emy,emax //敵のX,Y移動量 repeat emax //敵の座標と移動量と色を適当にセット ex(cnt)=double(rnd(ginfo_winx)) //座標 ey(cnt)=double(rnd(lmax)) emx(cnt)=double(rnd(110)-55)*0.02 //移動量 emy(cnt)=double(rnd(110)-55)*0.02 ecol(cnt)=rnd(192) //色 loop //メインループ *main redraw 0 color 255,255,255:boxf gosub *ework //敵を動かす gosub *edraw //敵を描画する redraw 1 await 15 goto *main //敵の移動処理 *ework //━━━━━━━━━ 肝の処理 ━━━━━━━━━ memset sort,0,lmax //バケツをからっぽにする。 //人数を0にするだけで前に配列にセットしたIDまで消さない。その方が高速。 //━━━━━━━━━ ここまで ━━━━━━━━━ repeat emax //敵は移動量分移動する ex(cnt)+=emx(cnt) ey(cnt)+=emy(cnt) //敵は範囲外に出たら折り返す if ex(cnt)<0 | ex(cnt)>=ginfo_winx:emx(cnt)=-emx(cnt):ex(cnt)=limitf(ex(cnt),0.0,ginfo_winx-1) if ey(cnt)<0 | ey(cnt)>=lmax:emy(cnt)=-emy(cnt):ey(cnt)=limitf(ey(cnt),0.0,lmax-1) //一応はここがソートになるんですが、実質ただの代入です。 //━━━━━━━━━ 肝の処理 ━━━━━━━━━ ln=int(ey(cnt)) //敵のY座標がバケツID poke sort,ln,peek(sort,ln)+1 //リクエストされたバケツIDに存在する敵の数+1 poke sort(peek(sort,ln)),ln,cnt //バケツに敵の配列IDを入れる //━━━━━━━━━ ここまで ━━━━━━━━━ loop return //敵の描画処理。奥から描画する。 *edraw gmode 0,32,64 //一見、二重ループに見えますが、敵の数ぶんしか処理しないので実質一重ループの重さです。 repeat lmax //最大Y座標ぶん繰り返す。 ln=cnt //バケツID。バケツは最大Y座標ぶん存在する。 repeat peek(sort,ln),1 //そのY座標にいる敵の数ぶん繰り返す。0人なら処理なし。 id=peek(sort(cnt),ln) //バケツに格納された敵の配列IDを取り出す。 hsvcolor ecol(id),255,255:grect ex(id),ey(id)+(ginfo_winy-lmax)/2 //敵を描画する loop loop return
実は私、バケツソートをまともにゲームで使ったことがないんですが^^;
爆速ですが使える局面が非常に限られている尖ったソートなので、
これを機会に有効活用できると良いですね。

ではでは失礼します。



リンク

2015/1/1(Thu) 17:36:19|NO.66777

むやみにスレを上げたくは無いのですが、
提示したソースにバグがありましたので失礼します。
ddim drawOrder,max ;描画オーダー
は、正しくは
dim drawOrder,max ;描画オーダー
です。一見正常に動いてるので気づきませんでした。



墨鴉

リンク

2015/1/1(Thu) 18:20:48|NO.66782

>>撃様
>>Drip様

サンプルソースまでありがとうございます。
皆様のおかげで無事開発が進められそうです。

ありがとうございました。



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