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


HSPTV!掲示板


未解決 解決 停止 削除要請

2017
0201
イナウサ3Dオブジェクトの当たり判定についての質問です。6解決


イナウサ

リンク

2017/2/1(Wed) 22:48:26|NO.78101

3Dオブジェクトで、四つの立体(building1〜building4)と自分(player)で四つの立体は必ず
静止していて、自分だけが動く感じです。自分が四つの立体と衝突すると、それ以上立体の
ある方へは動けなくそれ以外の方向なら動けるようなスクリプトを作ったのですが、上手く
いきません。スクリプトを載せるので、改善点を教えて下さい。
#include "hgimg3.as"

title"3D.data"
screen 0,ginfo(20),ginfo(21)-80,0,0,0

hgini

setcolor 0,0,255
addbox model,1.0,1.0
regobj player,model
setcoli player,1,2

setcolor 0,255,0
addbox model,100000.0,100000.0
regobj ground,model

setcolor 200,200,255
addbox model,5.0,50.0
regobj building1,model
setcoli building1,2,0

setcolor 200,200,255
addbox model,5.0,50.0
regobj building2,model
setcoli building2,2,0

setcolor 200,200,255
addbox model,5.0,50.0
regobj building3,model
setcoli building3,2,0

setcolor 200,200,255
addbox model,5.0,50.0
regobj building4,model
setcoli building4,2,0

setobjmode player,OBJ_XFRONT,0
//////////////////////////////////////////建物//////////////////////////////////////
setpos ground,0,50001.5,0
setang ground,0,0,0

setpos building1,22.5,0,-65
setang building1,0,0,0

setpos building2,-22.5,0,-65
setang building2,0,0,0

setpos building3,22.5,0,65
setang building3,0,0,0

setpos building4,-22.5,0,65
setang building4,0,0,0



x=0
bx=0
by=0
t=(100-x)*(100+x):y=sqrt(t)

repeat

///////////////////////////////////////キー入力及びその他////////////////////////////////
onkey 0       //キー入力を受け付けない
key=wparam
getkey w,87
getkey s,83
getkey d,39
getkey a,37



x=double(x)
p=double(p)
bx=double(bx)
by=double(by)
xy=double(xy)






if x=0{

}else{

if x>=0:if y>=0:xy=1.1/(x+y)
if x<=0:if y>=0:xy=1.1/(-x+y)
if x>=0:if y<=0:xy=1.1/(x-y)
if x<=0:if y<=0::xy=1.1/(x+y):xy=-xy
}


if xy<=0:xy=-xy





xx=x*xy
yy=y*xy
//////////////////////////////////移動するためのコード(当たり判定がある所)////////////////////////////////////

getcoli id ,player,5

if w=1{ ////////////////////wを押したとき(前進)
if id >=0{ /////////////当たり判定
//////////////////////跳ね返る為のコード(前進できないようにするため)
if p>=-100:if p<=100:by=by-yy:bx=bx-xx:if x=0:if y=100:by=by-1
if p>100:if p<=200:by=by-yy:bx=bx-xx:if x=0:if y=-100:by=by+1
if p>=-199:if p<=-100:by=by-yy:bx=bx-xx:if x=0:if y=-100:by=by+1

}else{
///////////////////////前進のためのコード
if p>=-100:if p<=100:by=by+yy:bx=bx+xx:if x=0:if y=100:by=by+1
if p>100:if p<=200:by=by+yy:bx=bx+xx:if x=0:if y=-100:by=by-1
if p>=-199:if p<=-100:by=by+yy:bx=bx+xx:if x=0:if y=-100:by=by-1
}


}

if s=1{/////////////////////sを押したとき(後進)
if id >=0{ /////////////当たり判定
///////////////跳ね返る為のコード(後進できないようにするため)
if p>=-100:if p<=100:by=by+yy:bx=bx+xx:if x=0:if y=100:by=by+1
if p>100:if p<=200:by=by+yy:bx=bx+xx:if x=0:if y=-100:by=by-1
if p>=-199:if p<=-100:by=by+yy:bx=bx+xx:if x=0:if y=-100:by=by-1
}else{
//////////////////////後進するためのコード
if p>=-100:if p<=100:by=by-yy:bx=bx-xx:if x=0:if y=100:by=by-1
if p>100:if p<=200:by=by-yy:bx=bx-xx:if x=0:if y=-100:by=by+1
if p>=-199:if p<=-100:by=by-yy:bx=bx-xx:if x=0:if y=-100:by=by+1
}
}


id=0

////////////////////////////////////////////////以下視点系//////////////////////////////////
if a=1{
p=p+1
if p=201:p=-199

if p>-100:if p<=100:x=p:t=(100-x)*(100+x):y=sqrt(t)
if p>100:if p<=200:x=x-1:t=(100-x)*(100+x):y=sqrt(t):y=-y

if p<=-100:x=x-1:t=(100-x)*(100+x):y=sqrt(t):y=-y


}

if d=1{
p=p-1
if p=-201:p=199

if p>=-100:if p<100:x=p:t=(100-x)*(100+x):y=sqrt(t)
if p<-100:if p>=-200:x=x+1:t=(100-x)*(100+x):y=sqrt(t):y=-y

if p>=100:if p<200:x=x+1:t=(100-x)*(100+x):y=sqrt(t):y=-y

}


ax=x+bx
ay=y+by


cx=double(cx):cx=-x/10+bx:cx=double(cx)

cy=double(cy):cy=-y/10+by:cy=double(cy)




cammode CAM_MODE_LOOKAT //カメラロック
setdir HGOBJ_CAMERA,ax,0,ay//カメラロック座標

setpos HGOJB_CAMERA,cx,-3,cy //左右、高さ、前後





setpos player,bx,0,by //左右、高さ、前後
//上下、左右、傾き




hgdraw
hgsync 10
loop



この記事に返信する


Drip

リンク

2017/2/3(Fri) 11:02:05|NO.78107

Dripです。

イナウサさん、こんにちは。当たり判定で難儀されていらっしゃるようですが、
今回ご提示されたスクリプトはやや混乱気味で、「ここを直して」と簡単に改善点を
指摘しにくい状態にあるように見えます。
また当たり判定にgetcoliを利用していらっしゃるようですが、
この命令は正方形の判定しかできない上に、判定対象は全て同じサイズにしないと
高速処理の恩恵を受けれないため、getcoliを使用せず、代わりにfindobj命令で
全ての建物を見つけて判定を行ったほうが良いかもしれません。
以上を踏まえ、以下にhgimg3での簡単な建物との当たり判定をするサンプルを示します。
壁4面の距離のうち一番距離が近い壁側にプレイヤーを押し出す処理が*hittest下に書かれています。
参考になれば幸いです。(getcoliで判定をした場合も押し出しの考え方自体は同じです。)
他にも様々なやりかたがあるので色々研究してみてくださいね。

#include "hgimg3.as" hgini randomize addbox box,2,2 //建物モデルbox(サイズを2にするとスケール値=ボックス中心から壁までの距離になる) #define psz 2 //プレイヤーの厚み(幅) setcolor 255:addbox m_plr,psz*2,psz*2 //プレイヤーモデルm_plr regobj plr,m_plr:setpos plr,50,0,50 //プレイヤーオブジェクトplrを画面中央に生成 repeat 40 //建物を40個適当に生成 regobj t,box:setcoli t,2 //建物のコリジョンIDは2 setpos t,rnd(100),0,rnd(100) //(※addboxで生成されたモデルはY拡大率(?)で明度が変わる仕様バグがあるようなので注意) setscale t,rnd(10)+1,2+rnd(3),rnd(10)+1 loop //カメラの位置と角度を設定 setpos HGOBJ_CAMERA,50,-100,100 setdir HGOBJ_CAMEEA,50,0,50 cammode CAM_MODE_LOOKAT gosub *hittest //プレイヤーがいきなり壁の中だと困るので最初に1回建物から押し出しておく //メインループ *main stick ky,15 //プレイヤーを移動させ、移動したら必ず建物との押し出し判定をする if ky&1:addpos plr,-0.5:gosub *hittest if ky&2:addpos plr,0,0,-0.5:gosub *hittest if ky&4:addpos plr,0.5:gosub *hittest if ky&8:addpos plr,0,0,0.5:gosub *hittest hgdraw hgsync 15 goto *main //プレイヤーと全ての建物の当たり判定をしてプレイヤーが建物の内側にいれば直近の壁側に押し出す処理 *hittest findobj ,2 //建物のコリジョンIDを検索対象にする getpos plr,px,t,pz //プレイヤーのX,Z座標をpx,pzに取得 repeat nextobj id:if id<0:break //建物が見つからなくなったら検索終了 getpos id,bx,t,bz //建物の壁のX,Z座標をbx,bzに取得 getscale id,sx,t,sz //建物の壁のX,Zサイズをsx,szに取得 //(※boxのサイズは2なのでスケールsx,sz=建物の中心から壁際までの距離になる) if absf(px-bx)<sx+psz & absf(pz-bz)<sz+psz:{ //プレイヤーの厚みを含めてプレイヤーが壁の内側に居る場合 //変数fvの配列0〜3に建物の壁 左、上、右、下 4枚の壁の中心座標とプレイヤー座標の距離を取得しておく fv(0)=absf(px-(bx-sx-psz)), absf(pz-(bz-sz-psz)) //左と上の壁 fv(2)=absf(px-(bx+sx+psz)), absf(pz-(bz+sz+psz)) //右と下の壁 min=fv:setpos plr,bx-sx-psz,0,pz //押し出すデフォルト座標は建物左側の壁 if fv(1)<min:min=fv(1):setpos plr,px,0,bz-sz-psz //もし上側の壁が近ければそちらに押し出す if fv(2)<min:min=fv(2):setpos plr,bx+sx+psz,0,pz //もし右側の壁が近ければそちらに押し出す if fv(3)<min:min=fv(3):setpos plr,px,0,bz+sz+psz //もし下側の壁が近ければそちらに押し出す getpos plr,px,t,pz //押し出し後のプレイヤー座標X,Zをpx,pzに取得しておく } loop return



イナウサ

リンク

2017/2/5(Sun) 11:57:48|NO.78134

わかりにくく大変申し訳ございませんでした。
これではどうでしょうか?
#include "hgimg3.as"

screen 0,ginfo(20),ginfo(21)-80,0,0,0

hgini

/////////////////////プレーヤーモデル

addbox model,1.0,1.0
regobj player,model


//////////////////////縦長の建物二つ

addbox model,5.0,50.0
regobj building1,model
addbox model,5.0,50.0
regobj building2,model

setpos building1,20,0,0
setang building1,0,0,0
setpos building2,-20,0,0
setang building2,0,0,0

repeat


onkey 0       //キー入力を受け付けない
key=wparam
getkey w,87
getkey s,83
getkey d,37
getkey a,39


if w=1:y=y+1
if s=1:y=y-1
if a=1:x=x+1
if d=1:x=x-1
setpos player,x,0,y

setpos HGOJB_CAMERA,0,0,100
hgdraw
hgsync 10
loop
これに付け足すような感じでお願いします。


//////////////////////縦長の建物二つ

addbox model,5.0,50.0
regobj building1,model
addbox model,5.0,50.0
regobj building2,model



Drip

リンク

2017/2/5(Sun) 18:15:28|NO.78140

こんにちは。

あくまでイナウサさんのスクリプトへの付け足しのみでのアドバイスをご希望とのことですが、
イナウサさんのスクリプトは殆どの座標や大きさが変数ではなく単なる数字や、
単一の変数で書かれていますので、非常に効率が悪く、
こちらがお出しできる情報も見難いものとなることを覚悟されてください。

それでは、今程イナウサさんがシンプルに修正してくださったスクリプト内に、

setpos player,x,0,y
という行があります。それを見つけ、その下の空間に以下のスクリプトを貼り付けてください。
これは私が先日書かせていただいたスクリプトの一部を書き換えたものです。

if absf(x-20)<2.5 & absf(y-0)<25:{ //building1の範囲内にプレイヤーが存在すれば判定を開始する min=absf(x-(20.0-2.5)):setpos player,20.0-2.5,0,y //デフォルトは左の壁に押し出す if absf(x-(20.0+2.5))<min:setpos player,20.0+2.5,0,y:min=absf(x-(20.0+2.5)) //右の壁のほうが近ければ右に押し出す if absf(y-(0.0-25.0))<min:setpos player,x,0,0.0-25.0:min=absf(y-(0.0-25.0)) //奥の壁のほうが近ければ奥に押し出す if absf(y-(0.0+25.0))<min:setpos player,x,0,0.0+25.0:min=absf(y-(0.0+25.0)) //手前の壁のほうが近ければ手前に押し出す getpos player,x,temp,y //プレイヤーの座標(x,y)を押し出された座標で更新 }
この状態で実行しますと(「これに付け足すような感じでお願いします。」は消してくださいね。)、
表示されて右手の建物(building1)に対して正確な当たり判定が発生します。
プレイヤーはどんなに頑張ってもbuilding1内に侵入できないことをご確認ください。

次はbuilding2の当たり判定ですが、
こちらもイナウサさんは物体に対して直接数値で座標とサイズを指定されていますから、
一々上記のようなコードを沢山書いて判定をしていく必要があります。
通常、プログラマーはそんな面倒なことはやりません。
じゃあ普通はどういったことをするの?となりますと、
私が先日貼り付けたスクリプトのような書き方で「建物」をグループ化して考え、
ループ処理でシンプルに記述します。書き方は他にも色々ありますが、
見た感じ一番シンプルになりそうな方法を選んで説明させていただいたつもりです。

もし、もはや今回の説明も意味不明で、building2の判定も書いて!となってしまっているようであれば、
恐れながらこれ以上現在のスクリプトを利用しての製作自体を見直すべきなのかもしれません。
3Dゲームの作成は一先ず保留にしてHSPの基本やプログラムの基礎を学んでみるのも良いかもしれません。



イナウサ

リンク

2017/2/5(Sun) 18:49:18|NO.78142

何度もすみません。
Dripさんの話を踏まえて考え直して、自分でDripさんのスクリプトを少し改良しました。

#include "hgimg3.as"
hgini

addbox model,2,2 //建物モデルbox(サイズを2にするとスケール値=ボックス中心から壁までの距離になる)
#define psz 4 //プレイヤーの厚み(幅)
setcolor 255
addbox plr,psz*2,psz*2 //プレイヤーモデルplr
regobj plr,plr
setpos plr,0,0,0 //プレイヤーオブジェクトplrを画面中央に生成

regobj building1,model
setcoli building1,2 //建物のコリジョンIDは2
setpos building1,10,0,0
//(※addboxで生成されたモデルはY拡大率(?)で明度が変わる仕様バグがあるようなので注意)
setscale building1,5,5,11

regobj building2,model
setcoli building2,2 //建物のコリジョンIDは2
setpos building2,-10,0,0
//(※addboxで生成されたモデルはY拡大率(?)で明度が変わる仕様バグがあるようなので注意)
setscale building2,5,5,11

//カメラの位置と角度を設定
setpos HGOBJ_CAMERA,0,-20,100
setdir HGOBJ_CAMEEA,0,0,0
cammode CAM_MODE_LOOKAT
x=double(x)
gosub *hittest //プレイヤーがいきなり壁の中だと困るので最初に1回建物から押し出しておく

//メインループ
repeat
setpos plr,x,0,y
onkey 0       //キー入力を受け付けない
key=wparam
getkey w,87
getkey s,83
getkey d,37
getkey a,39


if a=1:x=x+0.5:gosub*hittest
if d=1:x=x-0.5:gosub*hittest
hgdraw
hgsync 10
loop

//プレイヤーと全ての建物の当たり判定をしてプレイヤーが建物の内側にいれば直近の壁側に押し出す処理
*hittest
findobj ,2 //建物のコリジョンIDを検索対象にする
getpos plr,px,t,pz //プレイヤーのX,Z座標をpx,pzに取得
repeat
nextobj id:if id<0:break //建物が見つからなくなったら検索終了
getpos id,bx,t,bz //建物の壁のX,Z座標をbx,bzに取得
getscale id,sx,t,sz //建物の壁のX,Zサイズをsx,szに取得
//(※boxのサイズは2なのでスケールsx,sz=建物の中心から壁際までの距離になる)
if absf(px-bx)<sx+psz & absf(pz-bz)<sz+psz:{ //プレイヤーの厚みを含めてプレイヤーが壁の内側に居る場合
//変数fvの配列0〜3に建物の壁 左、上、右、下 4枚の壁の中心座標とプレイヤー座標の距離を取得しておく
fv(0)=absf(px-(bx-sx-psz)), absf(pz-(bz-sz-psz)) //左と上の壁
fv(2)=absf(px-(bx+sx+psz)), absf(pz-(bz+sz+psz)) //右と下の壁
min=fv:setpos plr,bx-sx-psz,0,pz //押し出すデフォルト座標は建物左側の壁
if fv(1)<min:min=fv(1):setpos plr,px,0,bz-sz-psz //もし上側の壁が近ければそちらに押し出す
if fv(2)<min:min=fv(2):setpos plr,bx+sx+psz,0,pz //もし右側の壁が近ければそちらに押し出す
if fv(3)<min:min=fv(3):setpos plr,px,0,bz+sz+psz //もし下側の壁が近ければそちらに押し出す
getpos plr,px,t,pz //押し出し後のプレイヤー座標X,Zをpx,pzに取得しておく
}
loop
return
改良したのですが、かすかにバグがあります。直して頂けないでしょうか?お願いします。
object plrはx座標=x、y座標=yで代入する形で作りたいのですが、その形で出来ますか?
教えて下さい。



Drip

リンク

2017/2/5(Sun) 19:14:39|NO.78143

こんにちは。

私のサンプルスクリプトを改善されたとのことですが、
これは私のスクリプトを理解せずにコピーしてしまっていることが顕著に現れてしまっています;
サンプルは好きなだけ弄り倒していただいて、自分の作品にされる際には、この最後のタイミングだけは、
1行ずつ落ち着いて、サンプルの1文1文が何を示しているのか理解しながら、
自分で書いていくことをお勧めします。

では今回ご提示されたおかしな挙動ですが、イナウサさんはプレイヤーのX,Z座標をx,yと指定しています。
しかし私の先日書いたスクリプトではプレイヤーのX,Z座標をpx,pzと指定しています。
そのため私のコードでプレイヤーの位置が正しく補正されても、それをイナウサさんが
メインループの始めに自分自身で座標を(x,0,y)と指定しなおしてしまっていますから、
おかしな動作になってしまっているのです。

更に、イナウサさんの全てのx,yの変数をpx,pzに直してもこの問題は解決されません。
*hittestへ行く前に、変数(px)の数値は変更されていますが、実際の物体の座標は変更されていないため、
*hittestの2行下にある getpos plr,px,t,pz で元の状態に戻されてしまいます。

重ね重ね、1行ずつ落ち着いて、サンプルの1文1文が何を示しているのか理解しながら、
自分で書いていくことをお勧めします。
正しく動作することよりも、なぜ現在のように動作するのか自分自身で理解することが上達への近道です。
そうすればおのずと解決策も見えてくるはずです。頑張ってください。



イナウサ

リンク

2017/2/5(Sun) 20:41:38|NO.78146

サポートありがとうございました。正常に当たり判定を出来るようになりました。ありがとうございました。

#include "hgimg3.as"
hgini

addbox model,2,2 //建物モデルbox(サイズを2にするとスケール値=ボックス中心から壁までの距離になる)
#define psz 4 //プレイヤーの厚み(幅)
setcolor 255
addbox plr,psz*2,psz*2 //プレイヤーモデルplr
regobj plr,plr
setpos plr,0,0,0 //プレイヤーオブジェクトplrを画面中央に生成

regobj building1,model
setcoli building1,2 //建物のコリジョンIDは2
setpos building1,10,0,0
//(※addboxで生成されたモデルはY拡大率(?)で明度が変わる仕様バグがあるようなので注意)
setscale building1,5,5,11

regobj building2,model
setcoli building2,2 //建物のコリジョンIDは2
setpos building2,-10,0,0
//(※addboxで生成されたモデルはY拡大率(?)で明度が変わる仕様バグがあるようなので注意)
setscale building2,5,5,11

//カメラの位置と角度を設定
setpos HGOBJ_CAMERA,0,-20,100
setdir HGOBJ_CAMEEA,0,0,0
cammode CAM_MODE_LOOKAT
x=double(x)
y=double(y)
//プレイヤーがいきなり壁の中だと困るので最初に1回建物から押し出しておく

//メインループ
repeat

onkey 0       //キー入力を受け付けない
key=wparam
getkey w,87
getkey s,83
getkey d,37
getkey a,39

if w=1:y=y-0.5
if s=1:y=y+0.5
if a=1:x=x+0.5
if d=1:x=x-0.5

setpos plr,x,0,y

//プレイヤーと全ての建物の当たり判定をしてプレイヤーが建物の内側にいれば直近の壁側に押し出す処理

findobj ,2 //建物のコリジョンIDを検索対象にする
getpos plr,px,t,pz //プレイヤーのX,Z座標をpx,pzに取得
repeat
nextobj id:if id<0:break //建物が見つからなくなったら検索終了
getpos id,bx,t,bz //建物の壁のX,Z座標をbx,bzに取得
getscale id,sx,t,sz //建物の壁のX,Zサイズをsx,szに取得
//(※boxのサイズは2なのでスケールsx,sz=建物の中心から壁際までの距離になる)
if absf(px-bx)<sx+psz & absf(pz-bz)<sz+psz:{ //プレイヤーの厚みを含めてプレイヤーが壁の内側に居る場合
//変数fvの配列0〜3に建物の壁 左、上、右、下 4枚の壁の中心座標とプレイヤー座標の距離を取得しておく
fv(0)=absf(px-(bx-sx-psz)), absf(pz-(bz-sz-psz)) //左と上の壁
fv(2)=absf(px-(bx+sx+psz)), absf(pz-(bz+sz+psz)) //右と下の壁
min=fv:setpos plr,bx-sx-psz,0,pz //押し出すデフォルト座標は建物左側の壁
if fv(1)<min:min=fv(1):setpos plr,px,0,bz-sz-psz //もし上側の壁が近ければそちらに押し出す
if fv(2)<min:min=fv(2):setpos plr,bx+sx+psz,0,pz //もし右側の壁が近ければそちらに押し出す
if fv(3)<min:min=fv(3):setpos plr,px,0,bz+sz+psz //もし下側の壁が近ければそちらに押し出す
getpos plr,px,t,pz //押し出し後のプレイヤー座標X,Zをpx,pzに取得しておく
}
loop
x=px
y=pz

hgdraw
hgsync 10

loop



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