|
 |
|
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

| |
|
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:{
と書いても結果は同じかと。
|
|
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

| |
|
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
ありがとうございます こちらも参考にさせていただきます
みなさんありがとうございました

| |
|