ページ 1 / 1
斜め坂について
Posted: 2009年12月03日(木) 04:15
by KEYONN_
現在、テスト用として、Windows用のアプリケーションを作成中です。
cc65ではなく、普通のゲームです。
そこで、アクションゲームの斜め坂を実験として、取り入れる事にしました。
現状は、坂道以外は正常にマップチップによる当たり判定が行われています。
当たり判定の方法は、こちらを読みました。
http://javagame.skr.jp/index.php?%A5%D6 ... E%D7%C6%CD
しかし、坂道の当たり判定がうまくいかず、困っています。
そこで、過去ログを読みました。
斜め45度の坂道ならば、zwiさんの投稿で
マップチップ内の相対x = キャラクタ座標のX座標 - マップチップの先端X座標
マップチップ内の相対y = マップチップ内の相対x
キャラクタ座標のY座標 = マップチップの先端Y座標 + マップチップ内の相対y
って具合でキャラクタのY座標が計算できます。
と書いてありました。
しかし、どうやって、マップチップの先端座標を取得するのか分からず、困っています。
また、マップチップに入った途端に計算するのか、それとも、三角形の当たり判定をすべきなのか
よく分かりません。どうか、教えてください。
Re:斜め坂について
Posted: 2009年12月03日(木) 15:45
by softya
>マップチップ内の相対x = キャラクタ座標のX座標 - マップチップの先端X座標
>マップチップ内の相対y = マップチップ内の相対x
>キャラクタ座標のY座標 = マップチップの先端Y座標 + マップチップ内の相対y
>って具合でキャラクタのY座標が計算できます。
>しかし、どうやって、マップチップの先端座標を取得するのか分からず、困っています。
キャラが立っているマップチップが分かるなら、マップチップの4点の座標は計算できると思いますが、それとも違う意味で聞いてらっしゃいます?
>また、マップチップに入った途端に計算するのか、それとも、三角形の当たり判定をすべきなのか
よく分かりません。どうか、教えてください。
斜めの坂と言ってもマップチップが32ドット程度なら、ドットサイズのサブマップチップだと考えてサブマップチップで当たり判定するのも一つの方法です。
こうなっている坂があるとして、
/□1
□□□2
ABC
B-1の位置の斜めの坂をドット単位(例として8ドットで表現)
□
□□
□□□
□□□□
□□□□□
□□□□□□
□□□□□□□
□□□□□□□□
の形状に並んでいるサブマップチップだと思って当たり判定します。
これなら現状の当たり判定の応用で出来ると思いますけど。どうでしょうか?
Re:斜め坂について
Posted: 2009年12月04日(金) 12:46
by KEYONN_
>キャラが立っているマップチップが分かるなら、マップチップの4点の座標は
>計算できると思いますが、それとも違う意味で聞いてらっしゃいます?
図を描きながら計算したら、簡単にマップチップの先端座標を取得できる事が分かりました。
例えば、sentanx=(Player.x+16)/32*32;sentany=(Player.y+31)/32*32;
で取得できそうです。
>斜めの坂と言ってもマップチップが32ドット程度なら、
>ドットサイズのサブマップチップだと考えてサブマップチップで当たり判定するのも一つの方法です。
ちょっとよく分かりません。サブマップチップとは何でしょうか?
とりあえず、現状のソースコードを載せるので、アドバイスを下さい。
Re:斜め坂について
Posted: 2009年12月04日(金) 20:07
by KEYONN_
一応、書いておきますが、自分なりには坂道のアルゴリズムを
考えているつもりです。
今まで、ずっと考えていましたが、答えが出せなかったのです。
このアップロードファイルは、ygs2k(YaneuraoGameScript2000)で
今までに考えたアルゴリズムをまとめたものです。
2Dゲームを作るにはまだ、経験不足か、実力が足りないという事でしょうか?
http://ppup.dip.jp/uploader/download/1259924801.zip
pass:tkoz
Re:斜め坂について
Posted: 2009年12月04日(金) 21:12
by KEYONN_
>>サブマップチップ
1ドットずつ当たり判定を行うという事で、よろしいでしょうか?
Re:斜め坂について
Posted: 2009年12月05日(土) 00:37
by softya
>ドットずつ当たり判定を行うという事で、よろしいでしょうか?
出かけていたので、返事が遅くなりました。申し訳ないです。
32X32ドットのブロックで当たり判定しているのを、坂道だけは1X1ドットのブロックがあると仮定して当たり判定します。
ブロックと接触しているかを判定しているルーチンをこのときだけ1X1で行うことになります。
>2Dゲームを作るにはまだ、経験不足か、実力が足りないという事でしょうか?
この手のアルゴリズムは試行錯誤を重ねるしか無いですね。
私も横スクロールは経験不足ですよ。平面スクロールのゲームは作った事があるんですが。
なので、一緒に考えていきましょう!
まぁ、ゲームなんてやりたい動きが出来るアルゴリズムを考え付くかが勝負って面がありますからね。
例えば「海腹川背」ってゲームがあるんですが、PSP版がすごく評判が悪いんです。SFC・PS版が原型にあるんですが、PSP版を担当したプログラマが原型のアルゴリズムを理解できない?あるいは力量不足で再現できなったためすごく出来の悪いゲームなりました。最新のDS版はSFC・PS版を担当したプログラマが作業したため完璧と言われています。PSP版の人も見ための動きからアルゴリズムを再現しようとしたんでしょうけどね。ソースは解読できなかったのかなぁと思います。
なので、思った動き出来る良いアルゴリズムを考え付くまで試行錯誤してみましょう。
すいませんソース見るの明日にさせてください。
よく検討してみますので。龍神録XNA 19章が終わったので少し余力が出来ました。
Re:斜め坂について
Posted: 2009年12月05日(土) 19:19
by softya
ソースコード見ました。
移動後に補正するには、坂道を登る場合に問題がある気がします。
とりあえず、このコードベースに坂道処理を考えて見ます。アルゴリズムを検討中でまだ時間が掛かりそうですけどね。例えばスーパーマリオ3あたりが坂道を実装しているので、ファミコンで出来る程度のなるべく軽い処理で検討中です。
Re:斜め坂について
Posted: 2009年12月06日(日) 17:14
by KEYONN_
>例えばスーパーマリオ3あたりが坂道を実装しているので、
>ファミコンで出来る程度のなるべく軽い処理で検討中です。
ファミコンで出来る程度のなるべく軽い処理ですか…私には思いつけません。
例えば、この間、ファミコンでブロック崩しを作ったのですが、
激重で、for(i=0;i<5;i++){for(j=0;j<16;j++){Block[j].…}}
といった処理を行ったのですが、メインループ内に
for文はきつい気がしました。
Re:斜め坂について
Posted: 2009年12月06日(日) 18:16
by softya
ごめんなさい。まだ出来てませんね。
なかなか手ごわいですわ。
>for(i=0;i<5;i++){for(j=0;j<16;j++){Block[j].…}}
ファミコンクラスのCPUで2次元配列はやばいでしょうね。
一次元配列で処理するようにしてください。
Block[x+y<<4]でアクセスするのがひとつの手。
あるいは、ポインタアクセスだけでループするのも手です。
pBlock = Block;
for( i=0 ; i<(5*16) ; i++,pBlock++ ) {
*pBlock
}
シーケンシャルな処理ならこれで十分です。
まぁ、アセンブラならもっと大技が駆使できるので高速化できます。
Re:斜め坂について
Posted: 2009年12月09日(水) 16:24
by KEYONN_
話が逸れますが、ブロック崩しで
ブロックとの当たり判定で関数Hit()を作りましたが、かなり重いです。
何が原因でしょうか?やはり、for文の2重ループでしょうか?
#define IDX (i+j<<4)
void Hit()
{
char i=0,j=0;
for(i=0;i<5;i++)
{
for(j=0;j<16;j++)
{
if(Block[IDX].flag==1)
{
if(Ball.y+4>Block[IDX].y && Ball.y<Block[IDX].y+8)
{
if(Ball.x+4==Block[IDX].x || Ball.x==Block[IDX].x+16)
{
Ball.mx*=-1;
SetDraw(j*2,i+2,0x00);
SetDraw(j*2+1,i+2,0x00);
SetScroll(0, 0);
return;
}
}
if(Ball.x+4>Block[IDX].x && Ball.x<Block[IDX].x+16)
{
if(Ball.y+4==Block[IDX].y || Ball.y==Block[IDX].y+8)
{
Ball.my*=-1;
SetDraw(j*2,i+2,0x00);
SetDraw(j*2+1,i+2,0x00);
SetScroll(0, 0);
return;
}
}
}
}
}
}
Re:斜め坂について
Posted: 2009年12月09日(水) 16:37
by softya
斜め坂は迷走中。
作ってみると色々なワナがありますね~。
◇形で当たり判定しないと坂上れない?など試行錯誤中。
>ブロック崩しで
こちらは、アセンブラコード見てみないと的確には答えられないかも知れません。
確かなのは、IDXの1重ループにして、IDXからiとjを求める様にしたほうが早いでしょう。
int IDX;
for( IDX=0 ; IDX<(5*16) ; IDX++ ) {
として
int i=IDX&0x0f;
int j=IDX>>4;
でi,jが求まります。
Blockも添え字処理のコード効率が悪いとすれば、ポインタに変えたほうが良いと思います。
cc65の最適化能力と6502の機械語コードの特性にもよるので断言は出来ませんが。
Re:斜め坂について
Posted: 2009年12月09日(水) 18:27
by softya
>cc65の最適化能力と6502の機械語コードの特性にもよるので断言は出来ませんが。
今cc65でアセンブラコードを出して見てみましたが、相当効率の悪いコードが出ている様に見えます。
6502の機械語やcc65をまともに使った事も無いですが、if(Block[IDX].flag==1)のコードだけ見ても、そうとう命令数が多いです。
;
; if(Block[IDX].flag==1)
;
ldx #$00
lda (sp),y
clc
iny
adc (sp),y
bcc L02D4
inx
L02D4: jsr shlax4
jsr mulax5
clc
adc #<(_Block)
sta ptr1
txa
adc #>(_Block)
sta ptr1+1
ldy #$04
lda (ptr1),y
cmp #$01
jne L0147
ちゃんと解読してませんが、添え字の計算が前半でshlax4はシフト?やらmulax5は掛け算?などの重そうな処理が使われています。処理の後半のBlockのflag参照も色々面倒ですね。
Re:斜め坂について
Posted: 2009年12月11日(金) 09:07
by KEYONN_
ネットカフェから書き込みです。
void Hit()
{
char i=0,j=0;
i=Ball.x/16;
j=Ball.y/8;
if(Block[IDX].flag==1)
{
if(Ball.y+4>Block[IDX].y && Ball.y<Block[IDX].y+8)
{
if(Ball.x+4==Block[IDX].x || Ball.x==Block[IDX].x+16)
{
Ball.mx*=-1;
SetDraw(j*2,i+2,0x00);
SetDraw(j*2+1,i+2,0x00);
SetScroll(0, 0);
return;
}
}
if(Ball.x+4>Block[IDX].x && Ball.x<Block[IDX].x+16)
{
if(Ball.y+4==Block[IDX].y || Ball.y==Block[IDX].y+8)
{
Ball.my*=-1;
SetDraw(j*2,i+2,0x00);
SetDraw(j*2+1,i+2,0x00);
SetScroll(0, 0);
return;
}
}
}
}
とかは無理でしょうか?
Re:斜め坂について
Posted: 2009年12月11日(金) 10:35
by softya
良いアイデアですよ。
ただ、同時に2~3ブロックに当たる可能性があるので最小限のループは必要ですね。
それとBlock[IDX]よりもポインタに変えた方が早いと思います。
こんな感じで。
Block_ *pBlock;
pBlock = &Block[IDX];
でポインタでアクセスです。
*pBlock
たぶん、これで早くなるかと。
Re:斜め坂について
Posted: 2009年12月12日(土) 22:28
by KEYONN_
*pBlockは、if(*pBlock->flag)でアクセスできますか?
正直ポインタはよく分かってません。
Re:斜め坂について
Posted: 2009年12月12日(土) 23:12
by softya
>*pBlockは、if(if(*pBlock->flag))でアクセスできますか?
>正直ポインタはよく分かってません。
cc65で高速化したかったら、ぜひポインタは覚えたほうが良いですよ。
今のままじゃ高速化にも限度があります。
この場合は
if(pBlock->flag)
が正解です。
*pBlockはポインタ参照してねって意味で書いただけです。
Re:斜め坂について
Posted: 2009年12月15日(火) 20:02
by KEYONN_
最小限のループはどうやって組めばいいか分かりません。
Block_ *pBlock;
for(i=-3;i<3;i++)
{
for(j=-3;j<3;j++)
{
pBlock=&Block[j];
if(pBlock->flag==1)
,,,???
}
}
どうやって組めばいいでしょうか?
Re:斜め坂について
Posted: 2009年12月15日(火) 22:45
by softya
ざっと単純に組んでみました。コンパイルしてないのでエラーが有るかもしれません。
実際にはボールの大きさ次第で当たり判定しなくても良い場合が考えられますので、まだ工夫の余地はあります。
あとは、本当はアセンブルリストを見比べながら効率のよいコードを探っていかないとダメですので、かなり時間が掛かります。流石にそこまで時間が無いのでご容赦ください。
Re:斜め坂について
Posted: 2009年12月16日(水) 12:42
by softya
補足として6502など貧弱なCPUの場合の高速化のテクニックですが、
(1)構造体配列や構造体ポインタからアクセスは出来るだけ避ける。ただの変数参照の方が早い。
(a)x
(b)pBlock->x
(c)Block[j].x
の順で重くなります。
(2)配列の添字は出来るだけ使わない。
→ Block[j]などは激烈に重い。
(3)事前に計算できるものは計算を済ませておく。
→ Ball.x+4など何度も計算させない。
(4)ローカル変数よりもグローバル変数の方が軽い。
理由はローカル変数がスタックポインタ相対アドレスの変数だからです。
などがあると思います。
思いついたやつだけですが・・・。
Re:斜め坂について
Posted: 2009年12月17日(木) 18:42
by KEYONN_
>>softyaさんへ
若干ソースを弄りましたが、うまく当たり判定が動きました。
ありがとうございました。
これで、ブロック崩しもうまく完成しそうです。
Re:斜め坂について
Posted: 2009年12月17日(木) 19:08
by softya
うまく動きましたか。良かったです。
斜め坂の方は時間が取れなくて保留中です。
もう少しまとまったらアップロードする予定ではいますけど。
→現在は斜め坂に刺さる場合があり処理を再検討中です。