|
|
2006/8/5(Sat) 12:39:13|NO.1799
ローグ系のRPGみたいに、自分を中心に視野の範囲だけ
マップのタイルを表示するスクリプトを書きたいんですが、上手くいきません。
長いプログラムで恐縮です。
下のように、視野が広がっていく軌跡をlosX,losYで予め指定しています。
このlosX,losYは90度分なので、vectorでx方向とy方向を変え、
4回(360度分)実行しています。
しかし、この方法だと視野の範囲が大きくなると対応できず
またプログラムとしてもなんだか無様です。
よろしくお願いします。
dim losX,10,10
dim losY,10,10
losY(0,0)=-1,-1,-1,-1,-1,-1
losX(0,0)= 0 ,1 ,0 ,0 ,0 ,0
losY(0,1)=-1,-1,-1,-1,-1, 1
losX(0,1)= 1 ,1 ,0 ,0 ,0 ,1
losY(0,2)=-1,-1,-1,-1 ,1 ,0
losX(0,2)= 0 ,1 ,1 ,1 ,0 ,0
losY(0,3)= 0,-1,-1,-1 ,0 ,0
losX(0,3)= 1 ,1 ,1 ,1 ,-1 ,0
losY(0,4)=-1,-1 ,0 ,0 ,0 ,1
losX(0,4)= 1 ,1 ,1 ,1 ,1 ,-1
losY(0,5)= 0,-1 ,0 ,0 ,0 ,0
losX(0,5)= 1 ,1 ,1 ,1 ,1 ,1
repeat 4
if cnt=0:vector=1,1
if cnt=1:vector=1,-1
if cnt=2:vector=-1,1
if cnt=3:vector=-1,-1
repeat 6
x=10:y=10
cnt2=cnt
repeat 6
x+=losX(cnt,cnt2)*vector(0)
y+=losY(cnt,cnt2)*vector(1)
pos x*16,y*16:mes"○"
loop
loop
loop
|
|
2006/8/5(Sat) 18:33:33|NO.1805
マップを全部描画しておいて、あとから不要な部分を黒で塗りつぶすというのもありかと思います。
このほうが綺麗に仕上がると思います。
でもとりあえずちょっと作ってみました。こんな感じですか?
dim map,10,10
dim chrxy,2
map(0,0) = 0,0,0,1,0,0,0,0,0,0 ;マップデータ
map(0,1) = 0,0,0,0,1,0,0,0,0,0
map(0,2) = 0,0,0,0,0,1,0,0,0,0
map(0,3) = 0,0,0,0,0,0,1,0,0,0
map(0,4) = 0,0,0,0,0,1,0,0,0,1
map(0,5) = 0,0,0,0,1,0,0,0,1,0
map(0,6) = 0,0,0,1,0,0,0,1,0,0
map(0,7) = 0,0,1,0,0,0,1,0,0,0
map(0,8) = 0,0,0,1,0,1,0,0,0,0
map(0,9) = 0,0,0,0,1,0,0,0,0,0
chrxy(0) = 5,5 ;キャラクタ座標
r = 5 ;視界半径
muki = 1 ;向き
*main
redraw 1 : await 16 : redraw 0 : color 255,255,255 : boxf : color 0,0,0
stick key
if key&1 : chrxy(0)-- : chrxy(1)++ : muki = 3 ;↓向きのイメージ
if key&2 : chrxy(1)-- : chrxy(0)-- : muki = 2 ; 2│1
if key&4 : chrxy(0)++ : chrxy(1)-- : muki = 1 ;─┼─
if key&8 : chrxy(1)++ : chrxy(0)++ : muki = 4 ; 3│4
if key&128 : end
title ""+muki
repeat 10
xx = cnt - chrxy(0) ;PCからのマップの相対座標
x = cnt
repeat 10
yy = cnt - chrxy(1) ;PCからのマップの相対座標
y = cnt
if (x>=0)&(y>=0){
if map(x,y)=1 { ;ここの行をコメントアウトした方が描画範囲は確認しやすい
;マップ描画(描画範囲は扇状)
if (xx*xx+yy*yy) <= r*r { ;描画範囲を円形に絞込み
;さらに描画範囲を絞り込んで扇状にする。
f = 0
if muki = 1 : if (chrxy(0)<=x)&(chrxy(1)>=y) : f = 1
if muki = 2 : if (chrxy(0)>=x)&(chrxy(1)>=y) : f = 1
if muki = 3 : if (chrxy(0)>=x)&(chrxy(1)<=y) : f = 1
if muki = 4 : if (chrxy(0)<=x)&(chrxy(1)<=y) : f = 1
if f = 1 : pos x*16,y*16 : mes "○"
}
}
}
loop
loop
pos chrxy(0)*16,chrxy(1)*16 : mes "●" ;PCの描画
goto *main
| |
|
2006/8/5(Sat) 18:59:11|NO.1807
すいません。言葉足らずでした。
自分を中心に外に向かってマップの表示をしているのは、
途中に壁や人などの障害があった時に、それ以降のマップを表示させないためです。
基本的には全方位見えていて、障害物があった時は、その先は見えないような感じです。
スクリーンショットでわかるかわかりませんが、
http://ivan.sourceforge.net/screenshots.html
このゲームみたいな感じです。
円形に絞り込むところのスクリプトは参考になりました。
ありがとうございます。
|
|
2006/8/5(Sat) 21:45:21|NO.1808
> 下のように、視野が広がっていく軌跡をlosX,losYで予め指定しています。
これの意味がなんとなくわかったような気がします。
losX,losYに書いた順番で調べていって途中に壁があったら以降を描画しないという感じでしょうか。
> しかし、この方法だと視野の範囲が大きくなると対応できず
なるほどマップを大きくすると対応が面倒ですね。
手作業なので「途中」の判定基準もあいまいになりそう。
参考になるかどうか分かりませんが、線分と矩形の衝突判定のサンプルをどうぞ。
http://hspwiki.nm.land.to/?%BE%D7%C6%CD%C8%BD%C4%EA
例えば壁とPCの間に線分を引いてその間に壁があったら、線分の一端側の壁は描画しない…とか。
|
|
2006/8/7(Mon) 11:46:12|NO.1839
ネットを探していて、スパイラルパスという方法を見つけました。
http://www.roguelikedevelopment.org/php/article/showArticle.php?path=development/LOS/articles/&article=Spiral%20Path%20FOV%20-%20Ray%20Dillinger.txt
やり方はわかるのですが、スクリプトになおすための規則性みたい
なのが頭が固くてわからないので、
もしわかる方がいましたら教えてください。
I
J8H
K927G
LA3@16F
MB45E
NCD
0
上の図で@がプレイヤーです。
1から0(0ではなくアルファベットのo)までが、
表示されるマップタイルの順番です。
まずプレイヤーの上下左右の1,2,3,4をチェックします。
1の場所に障害物がなければ、5,6,7を表示します。
2の場所に障害物がなければ、7,8,9を表示します。
3の場所に障害物がなければ、9,A,Bを表示します。
4の場所に障害物がなければ、B,C,5を表示します。
そして、表示されたタイルを元に、視界の広さ分だけ、
以下の作業をリピートします。*はチェックするタイルです。
表示されたタイルが右方向なら:
3
@1
2
の順番に新しいタイルをチェックする。
例えば最初の図でいうと、6が表示さえたらF,E,Gをチェックします。
表示されたタイルが右上なら
2
*1
をチェックします。左下なら
*1
2
とチェックします。
このような作業の繰り返しです。
長くなってすいません。
|
|
2006/8/8(Tue) 13:57:20|NO.1865
面白そうなのでチャレンジしてみました。
『スパイラルパス』とは異なるので、うおさんの希望に副えるものかどうかは微妙ですが・・・
マウスの左クリックで壁を描き、右クリックで壁を消せます。
中心から最外周ブロックに向けて、壁に当たるまで 光を描いて行く方式です。
速度は まずまずなんじゃないかと思いますが、どうでしょう?
dim map,43,43; 障害物記録用バッファ
; バッファは都合により正方形が効率がよい。
; そのため、画面上下に使用しない領域も含めて確保する。
screen 0,640,480
;###################################################################
*メイン
stick key,256+512
if (key & 256):tmpx=mousex/16+1: tmpy=mousey/16+6: map(tmpx,tmpy)=1
if (key & 512):tmpx=mousex/16+1: tmpy=mousey/16+6: map(tmpx,tmpy)=0
; ↑マウスの左クリックで障害物を置き、右クリックで消す。
gosub *視界チェック
redraw 0
color 0,0,50:boxf 0,0,640,480
repeat 30:cnty=cnt
repeat 40:cntx=cnt
tmpx1=cntx*16:tmpx2=tmpx1+16:tmpy1=cnty*16:tmpy2=tmpy1+16
if buf(cntx+1,cnty+6)=0{; 『可視』の時のみ・・・
color 255,255,100:boxf tmpx1,tmpy1,tmpx2,tmpy2
; ↑地面を明るく描く。
if map(cntx+1,cnty+6)=1{; 壁の表示
color 128,128,128:boxf tmpx1,tmpy1,tmpx2,tmpy2
}
}
loop
loop
redraw 1:await 30
goto *メイン
;##################################################################
*視界チェック
dim buf,43,43; 視界バッファを『不可視』で初期化
buf(21,21)=0
repeat 43:dxy=1.0*(cnt-21)*16/21
; ↑最外周ブロック(一辺分)についてのループ
flg1=0: flg2=0: flg3=0: flg4=0
repeat 21:tmp2=cnt
; ↑中心から最外周に向かってのループ
dxy2=dxy*tmp2: tmp3=21+int(dxy2/16)
buf(tmp3,21-tmp2)=flg1
if map(tmp3,21-tmp2)=1:flg1=1
buf(tmp3,21+tmp2)=flg2
if map(tmp3,21+tmp2)=1:flg2=1
buf(21-tmp2,tmp3)=flg3
if map(21-tmp2,tmp3)=1:flg3=1
buf(21+tmp2,tmp3)=flg4
if map(21+tmp2,tmp3)=1:flg4=1
loop
loop
return
| |
|
2006/8/8(Tue) 15:18:15|NO.1868
すみません。ちょっと修正します。
壁の向こうの『壁無し』が存在して初めて影になるようにしました。
これにより、壁が必要以上に不可視になるのを防いでいます。
その分ちょっと処理が重くなりました。
dim map,43,43; 障害物記録用バッファ
; バッファは都合により正方形が効率がよい。
; そのため、画面上下に使用しない領域も含めて確保する。
screen 0,640,480
ddim dxy,43
repeat 43
dxy(cnt)=(1.0*(cnt-21)*16)/21
loop; チェック用変数。あらかじめ計算しておく。
;###################################################################
*メイン
stick key,256+512
if (key & 256):tmpx=mousex/16+1: tmpy=mousey/16+6: map(tmpx,tmpy)=1
if (key & 512):tmpx=mousex/16+1: tmpy=mousey/16+6: map(tmpx,tmpy)=0
; ↑マウスの左クリックで障害物を置き、右クリックで消す。
gosub *視界チェック
redraw 0
color 0,0,50:boxf 0,0,640,480
repeat 30:cnty=cnt
repeat 40:cntx=cnt
tmpx1=cntx*16:tmpx2=tmpx1+16:tmpy1=cnty*16:tmpy2=tmpy1+16
if buf(cntx+1,cnty+6)<2{; 『可視』の時のみ・・・
color 255,255,100:boxf tmpx1,tmpy1,tmpx2,tmpy2
; ↑地面を明るく描く。
if map(cntx+1,cnty+6)=1{; 壁の表示
color 128,128,128:boxf tmpx1,tmpy1,tmpx2,tmpy2
}
}
loop
loop
redraw 1:await 30
goto *メイン
;##################################################################
*視界チェック
dim buf,43,43; 視界バッファを『不可視』で初期化
buf(21,21)=0
repeat 43:tmp1=cnt
; ↑最外周ブロック(一辺分)についてのループ
flg1=0: flg2=0: flg3=0: flg4=0
repeat 21:tmp2=cnt
; ↑中心から最外周に向かってのループ
dxy2=dxy(tmp1)*tmp2: tmp3=21+int(dxy2/16)
if (flg1=1)and(map(tmp3,21-tmp2)=0):flg1=2
buf(tmp3,21-tmp2)=flg1
if map(tmp3,21-tmp2)=1:flg1=1
if (flg2=1)and(map(tmp3,21+tmp2)=0):flg2=2
buf(tmp3,21+tmp2)=flg2
if map(tmp3,21+tmp2)=1:flg2=1
if (flg3=1)and(map(21-tmp2,tmp3)=0):flg3=2
buf(21-tmp2,tmp3)=flg3
if map(21-tmp2,tmp3)=1:flg3=1
if (flg4=1)and(map(21+tmp2,tmp3)=0):flg4=2
buf(21+tmp2,tmp3)=flg4
if map(21+tmp2,tmp3)=1:flg4=1
loop
loop
return
| |
|
2006/8/8(Tue) 16:10:23|NO.1872
たびたびすみません。
視界チェックのところの
視界バッファを『不可視』で初期化 は、『可視』で初期化の誤りです。
最初、『不可視のときは0』で作っていて、途中で変更したのを忘れてました。
|
|
2006/8/9(Wed) 14:48:08|NO.1902
投稿ありがとうございます。
かきしすさんのスクリプトを早速いじってみました。
シンプルなのに、視界の処理が感じがいいですね。
そのままゲームに組み込めそうになかったので
Cで書かれたLOSのソースを幾つかHSPになおして、
やっと動作するようになりました。
本命は再帰シャドウキャスティングという処理だったんですが、
苦労して打ち込んだのに動きませんでした。
|
|