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


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0312
iHatewe2Dゲームで円(壁)に沿ってリアルに移動する方法7解決


iHatewe

リンク

2020/3/12(Thu) 08:56:02|NO.89688

もうひとつ質問させていただきます すいません
2Dゲームの作成している中で自分の円と敵の円が衝突しているかの判定ができたので
物理的な移動(円(壁)に沿って移動)をしたく以下のようなスクリプトを作りました
しかし過去の自分の座標を使ってその位置に戻るだけなので
物理的な移動も出来ずキー操作の反応も悪くなるだけでした
どうすればリアルな移動ができるのでしょうか
obaqといったプラグインは使いたくありません
よろしくお願いします


// 自分 ms = 10.0 // 移動速度 mx = 0.5 * GINFO_WINX // 位置X my = 0.5 * GINFO_WINY // 位置Y mr = 20.0 // 半径 // 敵(岩) ex = 200.0 // 位置X ey = 200.0 // 位置Y er = 90.0 // 半径 b = "" repeat _mx = mx // 過去の位置X _my = my // 過去の位置Y // 移動 stick key, ( 2 + 1 + 8 + 4 + 32768 + 16384 + 131072 + 65536 ) // WASD移動 if (( key && 2 ) || ( key && 32768 )) { // ↑ or [W] my -= ms } if (( key && 1 ) || ( key && 16384 )) { // ← or [A] mx -= ms } if (( key && 8 ) || ( key && 131072 )) { // 下 or [S] my += ms } if (( key && 4 ) || ( key && 65536 )) { // → or [D] mx += ms } // 衝突判定 _er = er - ms // 調整 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if (isHit) { b = "してる" } else { b = "してない" } // 止まる if (isHit) { mx = _mx my = _my } // 状況 title strf( "自分(%.1f, %.1f) 衝突:%s", mx, my, isHit ) // 描画 redraw 0 color 255, 255, 255 boxf // 自分 color 255, 0, 0 circle ( mx - mr ), ( my - mr ), ( mx + mr ), ( my + mr ), 1 // 岩 color 100, 100, 100 circle ( ex - er ), ( ey - er ), ( ex + er ), ( ey + er ), 1 redraw 1 // 時間 await 16 loop



この記事に返信する


ソラ

リンク

2020/3/12(Thu) 15:21:48|NO.89692

こんな感じでどうでしょうか?
自機がぶつかった時、上下キーが入力されていたら左右に自機をずらしてみて、
左右が入力されていた場合は上下に自機をずらしています。

// 自分 ms = 10.0 // 移動速度 ms2= 1.0 //判定精度 mx = 0.5 * GINFO_WINX // 位置X my = 0.5 * GINFO_WINY // 位置Y mr = 20.0 // 半径 // 敵(岩) ex = 200.0 // 位置X ey = 200.0 // 位置Y er = 90.0 // 半径 b = "" repeat // 移動 stick key, ( 2 + 1 + 8 + 4 + 32768 + 16384 + 131072 + 65536 ) // WASD移動 key_W=(( key && 2 ) || ( key && 32768 )) // ↑ or [W] key_A=(( key && 1 ) || ( key && 16384 )) // ← or [A] key_S=(( key && 8 ) || ( key && 131072 ))// ↓ or [S] key_D= (( key && 4 ) || ( key && 65536 ))// → or [D] repeat (ms/ms2) _mx = mx // 過去の位置X _my = my // 過去の位置Y if key_W:my -= ms2 if key_A:mx -= ms2 if key_S:my += ms2 if key_D:mx += ms2 // 衝突判定 _er = er - ms2 // 調整 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if (isHit) { mx_=mx my_=my repeat 100 if key_W=0 & key_S=0:{ my=my_-(ms2*cnt);上にちょっとずらしてあたっているか確認 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if isHit=0:mx = _mx:my=my_-ms2:break my=my_+(ms2*cnt);下にちょっとずらしてあたっているか確認 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if isHit=0:mx = _mx:my=my_+ms2:break my=my_ } if key_A=0 & key_D=0:{ mx=mx_-(ms2*cnt);左にちょっとずらしてあたっているか確認 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if isHit=0:my = _my:mx=mx_-ms2:break mx=mx_+(ms2*cnt);右にちょっとずらしてあたっているか確認 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if isHit=0:my = _my:mx=mx_+ms2:break mx=mx_ } loop if isHit = 1:b = "してる" } else { b = "してない" } // 止まる if (isHit) { mx = _mx my = _my break } loop // 状況 title strf( "自分(%.1f, %.1f) 衝突:%s", mx, my, b) // 描画 redraw 0 color 255, 255, 255 boxf // 自分 color 255, 0, 0 circle ( mx - mr ), ( my - mr ), ( mx + mr ), ( my + mr ), 1 // 岩 color 100, 100, 100 circle ( ex - er ), ( ey - er ), ( ex + er ), ( ey + er ), 1 redraw 1 // 時間 await 16 loop



iHatewe

リンク

2020/3/12(Thu) 15:58:28|NO.89693

回答ありがとうございます。
確かにずらす方法はとってもいい案なのですが、
他のエンティティ(動く敵キャラ)なども実装する予定なので
>上下キーが入力されていたら左右に自機をずらしてみて、
>左右が入力されていた場合は上下に自機をずらしています。
キー入力での処理分岐は出来ればやらない方式で他の方法はあるのでしょうか
説明足らずですいません



ソラ

リンク

2020/3/12(Thu) 16:16:56|NO.89694

前回のフレームから
上下に移動してる場合は左右にずらす
左右に移動してる場合は上下にずらす
としているだけなので
if key_W=0 & key_S=0:{ を if (_my - my)=0:{
if key_A=0 & key_D=0:{ を if (_mx - mx)=0:{
と書いても結果は同じかと。



zakki

リンク

2020/3/12(Thu) 18:36:22|NO.89697

当たり判定を円のような単純な形状だけでやるならぶつからない位置を代数的に求められるので、単にちょうど接する位置に位置を補正するという手も。

// 衝突判定 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + er ), 2 ) ) // 押し出す if (isHit) { d = sqrt( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 )) nx = (mx - ex) / d ny = (my - ey) / d dr = (mr + er) - d mx += dr * nx my += dr * ny }



あらや

リンク

2020/3/12(Thu) 18:39:53|NO.89698

ソラさんの手法とは違いますが、
3Dゲームでよくある壁ずり移動を再現してみました。

ベクトルの正規化や内積などはモジュール化してあります。


#module // 2点間の距離 #defcfunc distance2d int x1, int y1, int x2, int y2 xlen = abs(x2 - x1); ylen = abs(y2 - y1); rcf = sqrt(powf(xlen, 2) + powf(ylen, 2)); return rcf; // 単位ベクトル(ベクトルの正規化) #deffunc VecNormalize2d var vx, var vy scl = sqrt( vx*vx + vy*vy); vx = vx / scl; vy = vy / scl; return; // ベクトルの内積 #defcfunc VecDot2d double x1, double y1, double x2, double y2 return x1*x2 + y1*y2; // 衝突している時の座標と角度を取得 #defcfunc GetColPos int x1, int y1, int cx, int cy, int r, var cpx, var cpy rad = atan(y1, x1); // 角度を取得 cpx = cos(rad) * r + cx; // 角度から円周上の座標Xを取得 cpy = sin(rad) * r + cy; // 角度から円周上の座標Yを取得 return rad; #global // 自分 ms = 10.0 // 移動速度 mx = 0.5 * GINFO_WINX // 位置X my = 0.5 * GINFO_WINY // 位置Y mr = 20.0 // 半径 // 敵(岩) ex = 200.0 // 位置X ey = 200.0 // 位置Y er = 90.0 // 半径 b = "" repeat _mx = mx // 過去の位置X _my = my // 過去の位置Y vecx = 0.0; // 進行方向のベクトルXを初期化 vecy = 0.0; // 進行方向のベクトルYを初期化 // 移動 stick key, ( 2 + 1 + 8 + 4 + 32768 + 16384 + 131072 + 65536 ) // WASD移動 if (( key && 2 ) || ( key && 32768 )) { // ↑ or [W] ;my -= ms vecy = -ms; } if (( key && 1 ) || ( key && 16384 )) { // ← or [A] ;mx -= ms vecx = -ms; } if (( key && 8 ) || ( key && 131072 )) { // 下 or [S] ;my += ms vecy = ms; } if (( key && 4 ) || ( key && 65536 )) { // → or [D] ;mx += ms vecx = ms; } mx += vecx; my += vecy; // 衝突判定 _er = er - ms // 調整 ;isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) isHit = (distance2d(mx, my, ex, ey) <= absf(mr + er)); if (isHit) { b = "してる" } else { b = "してない" } // 止ま……らない(横移動で真横に衝突した場合(縦も同じ)は止まることがある) if (isHit && ((vecx != 0.0) || (vecy != 0.0))) { ;mx = _mx ;my = _my rad = GetColPos(mx-ex, my-ey, ex, ey, er, cpx, cpy); // 衝突時、円周上の座標及び角度を取得 nvx = cpx - ex; // 法線ベクトルXを取得 nvy = cpy - ey; // 法線ベクトルYを取得 VecNormalize2d nvx, nvy; // 法線ベクトルを正規化 dvt = VecDot2d(vecx, vecy, nvx, nvy); // ベクトルの内積を取得 nvecx = vecx - dvt * nvx; // 壁に沿うベクトルXを算出 nvecy = vecy - dvt * nvy; // 壁に沿うベクトルYを算出 mx += nvecx; // 壁に沿った位置に修正X my += nvecy; // 壁に沿った位置に修正Y // 壁と自分が重なっている場合、壁の円周上に位置を修正する if( distance2d(mx, my, ex, ey) <= absf(mr + er) ) { rad = GetColPos(mx-ex, my-ey, ex, ey, er, cpx, cpy); mx = cos(rad)*(mr + er) + ex; my = sin(rad)*(mr + er) + ey; } } // 状況 title strf( "自分(%.1f, %.1f) 衝突:%s", mx, my, isHit ) // 描画 redraw 0 color 255, 255, 255 boxf // 自分 color 255, 0, 0 circle ( mx - mr ), ( my - mr ), ( mx + mr ), ( my + mr ), 1 // 岩 color 100, 100, 100 circle ( ex - er ), ( ey - er ), ( ex + er ), ( ey + er ), 1 redraw 1 // 時間 await 16 loop



玄冬

リンク

2020/3/12(Thu) 23:47:03|NO.89700

こう?(変えた所に;つけてます)

// 自分 ms = 10.0 // 移動速度 mx = 0.5 * GINFO_WINX // 位置X my = 0.5 * GINFO_WINY // 位置Y mr = 20.0 // 半径 // 敵(岩) ex = 200.0 // 位置X ey = 200.0 // 位置Y er = 90.0 // 半径 b = "" repeat // _mx = mx // 過去の位置X // _my = my // 過去の位置Y // 衝突判定 tX = mX - eX; tY = mY - eY; tR = mr + er; //_er = er - ms // 調整 isHit = ( powf(( tX ), 2 ) + powf(( tY ), 2 ) <= powf(( tR ), 2 ) ); if (isHit) { b = "してる" } else { b = "してない" } // 移動 stick key, ( 2 + 1 + 8 + 4 + 32768 + 16384 + 131072 + 65536 ) // WASD移動 if (( key && 2 ) || ( key && 32768 )) { // ↑ or [W] my -= ms if isHit {; if 0 < tX {; mX = eX + sqrt(tR * tR - tY * tY); } else{; mX = eX - sqrt(tR * tR - tY * tY); }; }; } if (( key && 1 ) || ( key && 16384 )) { // ← or [A] mx -= ms if isHit {; if 0 < tY {; mY = eY + sqrt(tR * tR - tX * tX); } else{; mY = eY + sqrt(tR * tR - tX * tX); }; }; } if (( key && 8 ) || ( key && 131072 )) { // 下 or [S] my += ms if isHit {; if 0 < tX {; mX = eX + sqrt(tR * tR - tY * tY); } else{; mX = eX - sqrt(tR * tR - tY * tY); }; }; } if (( key && 4 ) || ( key && 65536 )) { // → or [D] mx += ms if isHit {; if 0 < tY {; mY = eY + sqrt(tR * tR - tX * tX); } else{; mY = eY + sqrt(tR * tR - tX * tX); }; }; } /* // 止まる if (isHit) { mx = _mx my = _my } */ // 状況 title strf( "自分(%.1f, %.1f) 衝突:%s", mx, my, isHit ) // 描画 redraw 0 color 255, 255, 255 boxf // 自分 color 255, 0, 0 circle ( mx - mr ), ( my - mr ), ( mx + mr ), ( my + mr ), 1 // 岩 color 100, 100, 100 circle ( ex - er ), ( ey - er ), ( ex + er ), ( ey + er ), 1 redraw 1 // 時間 await 16 loop



iHatewe

リンク

2020/3/13(Fri) 13:52:21|NO.89709

>NO.89692 NO.89694
>if key_W=0 & key_S=0:{ を if (_my - my)=0:{
>if key_A=0 & key_D=0:{ を if (_mx - mx)=0:{
なるほど これでも同じなのですね ありがとうございます

>NO.89697
円周上に位置を調整すればいいということですかね ありがとうございます

>NO.89698
のコードと私なりに考えたものと少し似ている部分がありました
私のものでは跳ねてしまいますが一応中には多分入らないと思います
ありがとうございます

// 自分 ms = 10.0 // 移動速度 mx = 0.5 * GINFO_WINX // 位置X my = 0.5 * GINFO_WINY // 位置Y mr = 20.0 // 半径 // 敵(岩) ex = 200.0 // 位置X ey = 200.0 // 位置Y er = 90.0 // 半径 b = "" repeat _mx = mx // 過去の位置X _my = my // 過去の位置Y // 移動 stick key, ( 2 + 1 + 8 + 4 + 32768 + 16384 + 131072 + 65536 ) // WASD移動 if (( key && 2 ) || ( key && 32768 )) { // ↑ or [W] my -= ms } if (( key && 1 ) || ( key && 16384 )) { // ← or [A] mx -= ms } if (( key && 8 ) || ( key && 131072 )) { // 下 or [S] my += ms } if (( key && 4 ) || ( key && 65536 )) { // → or [D] mx += ms } // 衝突判定 _er = er - ms // 調整 isHit = ( powf(( mx - ex ), 2 ) + powf(( my - ey ), 2 ) <= powf(( mr + _er ), 2 ) ) if (isHit) { b = "してる" } else { b = "してない" } // 止まる if (isHit) { just = 2.0 // 調整の為の定数 angle = atan(( ey - my ), ( ex - mx )) mx -= ( ms * just * cos(angle) ) my -= ( ms * just * sin(angle) ) } // 状況 title strf( "自分(%.1f, %.1f) 衝突:%s", mx, my, isHit ) // 描画 redraw 0 color 255, 255, 255 boxf // 自分 color 255, 0, 0 circle ( mx - mr ), ( my - mr ), ( mx + mr ), ( my + mr ), 1 // 岩 color 100, 100, 100 circle ( ex - er ), ( ey - er ), ( ex + er ), ( ey + er ), 1 redraw 1 // 時間 await 16 loop

>NO.89700
ありがとうございます こちらも参考にさせていただきます
みなさんありがとうございました



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