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


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0606
1キーによる滑らかな移動をする方法を知りたい13解決


1

リンク

2020/6/6(Sat) 09:42:33|NO.90697


#const LEFT 1 #const UP 2 #const RIGHT 4 #const DOWN 8 ; 移動キー dim directionKeys, 8 directionKeys(0) = UP directionKeys(1) = UP || RIGHT directionKeys(2) = RIGHT directionKeys(3) = RIGHT || DOWN directionKeys(4) = DOWN directionKeys(5) = DOWN || LEFT directionKeys(6) = LEFT directionKeys(7) = LEFT || UP ; directionDegree = ( 360.0 / length( directionKeys ) ) x = 0.5 * GINFO_WINX y = 0.5 * GINFO_WINY repeat ; 角度取得 radian = atan(( mousey - y ), ( mousex - x )) degree = rad2deg(radian) ; 調整 degree += ( 180 + ( 360 - 90 ) ) degree \= 360 ; 適用 key = 0 foreach directionKeys if ( ( degree >= ( directionDegree * cnt ) ) && ( degree <= ( directionDegree * ( 1 + cnt ) ) ) ) { key = directionKeys(cnt) break } loop ; 移動 s = "" if ( key && LEFT ) { x -= 2.0 s += "←" } if ( key && UP ) { y -= 2.0 s += "↑" } if ( key && RIGHT ) { x += 2.0 s += "→" } if ( key && DOWN ) { y += 2.0 s += "↓" } ; 描画開始 redraw 0 ; 背景 color 255, 255, 255 boxf ; 自機 color 255, 0, 0 circle ( x - 8 ), ( y - 8 ), ( x + 8 ), ( y + 8 ), 1 ; 情報 color 0, 0, 0 pos 20, 20 mes "角度:" + degree + "° キー:" + s ; 描画終了 redraw 1 ; タイマー await 16 loop

stick命令のような処理 と その角度に合わせたキー移動を行う処理を作りました。
[例] 自機(赤)が90°の方向に向いていたら[→]キーを押す。ということです

しかし、この処理では8方向にしか対応していなく、それにより動きがカクカクとしています。
滑らかにキー移動をするにはどうすればいいでしょうか?

※あえてキー入力による移動をしています



この記事に返信する


あらや

リンク

2020/6/6(Sat) 13:18:49|NO.90698

単純に目標に向かって移動するという事ならば

; 移動 x += cos(radian) * 2.0; 2.0は移動速度 y += sin(radian) * 2.0;

このようにすればスムーズになりますが

キー入力で8方向だけとなると
どうしてもカクカクしてしまうのは
仕方がないかと思います。
(ジョイスティックのように全方向を感知出来るのならば別ですが)

せいぜい、斜め移動時には縦と横両方に2.0を加減算するのではなく
(2.0 * 1.0 / √2)を加減算すれば縦横移動と斜め移動との速度差が
少しは改善出来るのかも?というくらいでしょうか。



1

リンク

2020/6/6(Sat) 16:08:35|NO.90699

> ※あえてキー入力による移動をしています
というのは

x += cos(radian) * 2.0; 2.0は移動速度 y += sin(radian) * 2.0;
ではないという意味でしたが分かりずらかったですね。

10°方向だったら縦方向に移動するようなものなので、
「↑」を押しながら「→」を少しずつ押すみたいな処理を作りたいです。
言葉だと上手く表現できないな... すいません

一応、例を挙げます
・45° 「↑」「→」を同時に押す
・170°「↓」キーを押しながら「→」を少しずつ押す
・350°「↑」キーを押しながら「←」を少しずつ押す



Drip

リンク

2020/6/6(Sat) 16:48:05|NO.90700

Dripです。
1さん、こんにちは。
プレイヤーと同条件で動作する敵AIの設計でしょうか?面白いことをされていますね。

スクリプトを拝見させていただきますと、あくまで8方向のキーを押し分けて、
「あたかも人間が操作しているように中途半端な角度にいる目標へも
 なるべく直線で向かっていくような動きでキー入力操作をシミュレーションしたい」
という解釈でよろしいのでしょうか?そうしますと1さんのスクリプト中の
「; 適用」とされる範囲(7行全て)を以下の処理で置き換えてください。

; 適用 key=0 //キーをリセットする #define myRatio 20 //何フレーム使って斜めの押し分けを行うかを定義。 //この値は大きい値ほど悠長な動きになるが、その分補正割合は正確になる。 //逆に小さい程機敏に補正を行うが、正確さに欠けるようになる。10〜20が良い具合です。 myHorizon=double(mousex-x) //目標座標への水平方向の距離 myVertical=double(mousey-y) //目標座標への垂直方向の距離 myTotal=absf(myHorizon)+absf(myVertical) //水平・垂直移動のみで移動した場合の目標座標までの距離 if myTotal>2:{ //目標座標に到達していない場合、キーの押し下げ処理を行う //次の1行の判定は現在の目標角度が中途半端な角度であるかを判定し、 //中途半端な角度を何フレーム間補正してキー入力を行うか判定するためのif文である。 //タイマーをレートと見て、水平距離と垂直距離の差がレートを上回った場合に限り単純なキー入力を行う。 //つまり、より正確に斜めの位置に目標が存在する場合ほど以下の単純なキー入力処理が実行されることになる。 if myTimer\myRatio > abs(abs(myHorizon/myTotal*myRatio) - abs(myVertical/myTotal*myRatio)):{ //単純なキー入力処理では目標が少しでも斜めの位置にあれば斜め入力を行い、 //完全に水平・完全に垂直な位置にいる場合に限って単キーの入力を行う。 if myHorizon<0:key|=LEFT if myHorizon>0:key|=RIGHT if myVertical<0:key|=UP if myVertical>0:key|=DOWN }else{ //タイマーをレートと見て、水平距離と垂直距離の差がレートを下回っている場合は単キーの補正入力を行う。 //この処理は例えば目標が10時方向(左左上と言いましょうか)に存在する場合、 //プレイヤーは左上にキーを入力しながらも時々左キーのみをプッシュしてより真っ直ぐ目標に向かおうとします。 //この処理ではそれを行います。 if absf(myHorizon)>absf(myVertical):{ //標的がより水平方向に離れている場合、水平方向のキーのみを補正入力する if myHorizon<0:key|=LEFT:else:key|=RIGHT //目標の位置に応じて左・右を押し分ける }else{ //標的がより垂直方向に離れている場合、垂直方向のキーのみを補正入力する if myVertical<0:key|=UP:else:key|=DOWN //目標の位置に応じて上・下を押し分ける } } } myTimer++ //入力レートの判定に使うためのタイマーを常時加算する
この修正によってまるで人間が操作しているような入力操作を行うようになります。
しかしこれでは角度があまりにガクガクしているので何とかならないか?
というところまで追求する場合は、敵に角度の概念を持たせる必要があります。
上記の修正に加え、「; 移動」とされる範囲(17行全て)を以下の処理で置き換えてください。

; 移動 s = "" #define angRatio 5 //何度ずつ角度を変えるかを定義。 //大きいほど俊敏に角度を変えるが大きすぎるとガクガクする //小さい程滑らかに角度を変えるが小さすぎるとなかなか目標の角度を向かない //敵の速度によるが、3〜10がいい具合 moveKeyOnly=key&15 //keyから移動キーのみを取り出し、以下の判定でa_tgtに押されたキーの角度を代入する if moveKeyOnly=UP: a_tgt=directionDegree*0:s+="↑" if moveKeyOnly=UP+RIGHT: a_tgt=directionDegree*1:s+="↑→" if moveKeyOnly=RIGHT: a_tgt=directionDegree*2:s+="→" if moveKeyOnly=RIGHT+DOWN: a_tgt=directionDegree*3:s+="→↓" if moveKeyOnly=DOWN: a_tgt=directionDegree*4:s+="↓" if moveKeyOnly=DOWN+LEFT: a_tgt=directionDegree*5:s+="↓←" if moveKeyOnly=LEFT: a_tgt=directionDegree*6:s+="←" if moveKeyOnly=LEFT+UP: a_tgt=directionDegree*7:s+="←↑" if s!"":{ //何らかのキーが入力された場合 t=a_tgt-a:if t<-180:t+=360:else:if t>180:t-=360 //tに自分の角度(a)と目標角度(a_tgt)の差を求める(-180〜180の範囲で) if t<0:a-=angRatio:else:a+=angRatio //差の出た方向に自分の角度(a)を操作する if a<-180:a+=360:else:if a>180:a-=360 //自分の角度(a)が(-180〜180の範囲に収まるようにする) x+=sin(deg2rad(-a+180))*2.0 //水平方向の移動を反映 y+=cos(deg2rad(-a+180))*2.0 //垂直方向の移動を反映 }
敵の座標を管理する変数x,yに加え、敵の角度を管理する変数aに従ってx,yを移動させるので
より動きが滑らかになります。

今回はあくまで8方向のキープッシュをシミュレーションしながら
なるべく滑らかに移動させるという縛りですので出来ることに限界はありますが、
自分なりに最適な動作になるよう色々アイデアを凝らしてみると面白いかと思います。
がんばってください。



kanamaru

リンク

2020/6/6(Sat) 16:51:30|NO.90701

正直内容を完全に理解しているわけではないのですが、
左右キーで回転、上キーで前進、下キーで後進という風にすればいいのでは?
昔そういう操作方法のゲームで遊んだ記憶があります。
1さんの考えた方法もわからなくもないんですが、
ちょっと慣れるまで時間がかかりそうです。



Drip

リンク

2020/6/6(Sat) 17:00:43|NO.90702

追伸、1さんのスクリプトを私が提示した「;適用」処理に修正した場合、1さんの
「; 角度取得」と「; 調整」の処理が全て不要となり、消しても動作するようになります。
私の提示行数が多くオエッとなるかもしれませんが、コメントに多くを割いておりますので
一行一行処理を負いながら理解していただければ幸いです。



kanamaru

リンク

2020/6/6(Sat) 17:03:11|NO.90703

Dripさんの投稿見て気付いたんですけど勘違いしていたみたいです。
操作するのはプログラムですか。
質問中のプログラムを実行すればよかった。
とはいえど、僕が提案した手法にすればプログラムが操作するにしても
人が操作するのと差が少なくなりそうです。



沢渡

リンク

2020/6/6(Sat) 17:24:10|NO.90704

なんかAIだとか、話の趣旨がズレているような気がするのですが……。
スレ主さんがしたいことは、あくまでもNO.90699の
>・45° 「↑」「→」を同時に押す
>・170°「↓」キーを押しながら「→」を少しずつ押す
>・350°「↑」キーを押しながら「←」を少しずつ押す
といった、微妙な角度への動きなのですよね?
こんな↓感じで、X方向の速度とY方向の速度がキーのON/OFFに合わせて加速・減速するような
処理にしてみましたが、どうでしょうか?

#const LEFT 1 #const UP 2 #const RIGHT 4 #const DOWN 8 #const acc 0.3 //1フレームあたりの加速度(decよりも大きな値にすること) #const dec 0.2 //1フレームあたりの減速度(減速は常に行う) #const spd_max 3.0 //最大速度 // #define use_key //←これのコメントアウトを外した場合はマウスではなくキーボードの←↑→↓で入力する ; 移動キー dim directionKeys, 8 directionKeys(0) = UP directionKeys(1) = UP || RIGHT directionKeys(2) = RIGHT directionKeys(3) = RIGHT || DOWN directionKeys(4) = DOWN directionKeys(5) = DOWN || LEFT directionKeys(6) = LEFT directionKeys(7) = LEFT || UP ; directionDegree = ( 360.0 / length( directionKeys ) ) x = 0.5 * GINFO_WINX y = 0.5 * GINFO_WINY xs = 0.0 //X方向の速度 ys = 0.0 //Y方向の速度 #ifdef use_key degree=0.0 #endif repeat #ifndef use_key ; 角度取得 radian = atan(( mousey - y ), ( mousex - x )) degree = rad2deg(radian) ; 調整 degree += ( 180 + ( 360 - 90 ) ) degree \= 360 ; 適用 key = 0 foreach directionKeys if ( ( degree >= ( directionDegree * cnt ) ) && ( degree <= ( directionDegree * ( 1 + cnt ) ) ) ) { key = directionKeys(cnt) break } loop #else //キーボードから入力 stick key,15 #endif ; 移動 s = "" if ( key && LEFT ) { xs -= acc s += "←" } if ( key && UP ) { ys -= acc s += "↑" } if ( key && RIGHT ) { xs += acc s += "→" } if ( key && DOWN ) { ys += acc s += "↓" } //速度0に向かって減速 if xs>0 : xs=limitf(xs-dec,0.0,spd_max) : else : xs=limitf(xs+dec,-spd_max,0.0) if ys>0 : ys=limitf(ys-dec,0.0,spd_max) : else : ys=limitf(ys+dec,-spd_max,0.0) //速度の最大値を取得 x+=xs y+=ys ; 描画開始 redraw 0 ; 背景 color 255, 255, 255 boxf ; 自機 color 255, 0, 0 circle ( x - 8 ), ( y - 8 ), ( x + 8 ), ( y + 8 ), 1 ; 情報 color 0, 0, 0 pos 20, 20 mes "角度:" + degree + "° キー:" + s ; 描画終了 redraw 1 ; タイマー await 16 loop



Drip

リンク

2020/6/6(Sat) 18:01:30|NO.90705

沢渡さん

>なんかAIだとか、話の趣旨がズレているような気がするのですが……。

これは私に対しての苦言でしょうか?
私はAIについて話してはいないかと思うのですが、趣旨がどうずれていたのでしょうか…
問題の箇所があればご指摘いただければ幸いです。
私は沢渡さんのように勝手に速度の概念を追加したりすることなく
正しくNO.90699の要望にも合致した修正を先に提示したつもりですが…。


kanamaruさん
1さん

kanamaruさんの考え方は1さんの設計された操作システムそのものを覆すやり方となりますね。
「ドラクエ操作」だったものが「バイオハザード操作」になるイメージでしょうか…
それを行うのであれば先ほどの私の修正は適用せず、当初の1さんのスクリプトの
「; 移動」とされる範囲(17行全て)を以下の処理で置き換えることで実現されます。

; 移動 s="" key=UP //常時進行キーをプッシュ #define angRatio 10 //何度ずつ角度を変えるかを定義。 t=degree-a:if t<-180:t+=360:else:if t>180:t-=360 //tに自分の角度(a)と目標角度(a_tgt)の差を求める(-180〜180の範囲で) if t<0:key|=LEFT:else:key|=RIGHT //差の出た方向に自分の角度を操縦する if key&LEFT:a-=angRatio:s+="←" //左を向くキーが押されている場合自分の角度を左に if key&RIGHT:a+=angRatio:s+="→" //右を向くキーが押されている場合自分の角度を右に if a<-180:a+=360:else:if a>180:a-=360 //自分の角度(a)が(-180〜180の範囲に収まるようにする) if key&UP:{ //上キーが押されている場合向いてる方向に進行する s+="↑" x+=sin(deg2rad(-a+180))*2.0 //水平方向移動 y+=cos(deg2rad(-a+180))*2.0 //垂直方向移動 }
但し、この方法ですとNO.90699で1さんが挙げられた考え方からは離れ、
またキー操作は常に相対角度に縛られてしまい、
軽快な動きを作ることが難しくなることを覚悟する必要があるかもしれませんね。
色々試されてみてください。



沢渡

リンク

2020/6/6(Sat) 18:18:03|NO.90706

「苦言」などという強いことを言ったつもりはなかったのですが、
気を悪くなさったようなら申し訳ありませんでした。
貴殿の書き込み一部だけを読んで早合点しての発言でした。
無礼かつ思慮に欠けた発言、お詫び申し上げます。

>私は沢渡さんのように勝手に速度の概念を追加したりすることなく
デジタル8方向入力で170°とか350°のような微妙な角度への移動を実現するとなったら、
私の頭では速度の概念を導入する以外の方法は思い浮かびませんでした。



1

リンク

2020/6/6(Sat) 21:49:39|NO.90707

NO.90700 Drip様
>プレイヤーと同条件で動作する敵AIの設計でしょうか?面白いことをされていますね。
おっと鳥肌が、エスパーですか?なんてのは置いといて...

>あたかも人間が操作しているように中途半端な角度にいる目標へも
> なるべく直線で向かっていくような動きでキー入力操作をシミュレーションしたい」
>という解釈でよろしいのでしょうか
理解して頂き嬉しいです。

>「; 適用」とされる範囲(7行全て)を以下の処理で置き換えてください。
この時点で私の理想通りの動きなっています。ありがとうございます。

>上記の修正に加え、「; 移動」とされる範囲(17行全て)を以下の処理で置き換えてください。
追加修正コードありがとうございます。少し難しそうと思いますが何とか理解できそうです。


NO.90701 NO.90703 kanamaru様
>左右キーで回転、上キーで前進、下キーで後進という風にすればいいのでは?
申し訳ございません。どうしてもキー移動(4方向WASD)による処理を行いたいものなので...


NO.90702 Drip様
>追伸、1さんのスクリプトを私が提示した「;適用」処理に修正した場合、1さんの
>「; 角度取得」と「; 調整」の処理が全て不要となり、消しても動作するようになります。
了解しました。とても分かりやすい説明、ありがとうございます。


NO.90704 沢渡様
フィボナッチ数列の螺旋みたいな動きでとても面白いです。
参考にさせていただきます。


皆さんコードの解説本当にありがとうございました。
今回は一番理想的な移動を実現してくれたDrip様のコードを改変使用させて頂きます。
他の方のコードも参考にさせていただきます。皆さん本当にありがとうございました。
正直、私の実現したいことが完璧に見破られたことが一番ビックリですw



2

リンク

2020/6/12(Fri) 19:46:07|NO.90749

あれ? HSPにはない&&や||があるのはなんで?



2

リンク

2020/6/12(Fri) 20:13:52|NO.90752

これってドラクエのようなマス目でキャラを動かしたいってことですか?
ラジアン値を1マス分に変換するとかだめでしょうか?



あらや

リンク

2020/6/12(Fri) 23:36:03|NO.90753

>あれ? HSPにはない&&や||があるのはなんで?
無いのではなく、有るけれど区別されていないだけです。

ほかの言語では==、&&、||などはif文などでの条件式でしか使えず
=は代入、&や|は計算式で使用するものとして区別されていますが、
HSPでは&、&&、andは全て同じ意味になり、
|、||、orも同じ意味になります。

ちなみに=、==も同じ意味になります。


a = 1; b == 2; // ==でも普通に代入可能 c1 == a & b; c2 == a && b; c3 == a and b; d1 = a | b; d2 = a || b; d3 = a or b; mes "a = "+a; mes "b = "+b; mes "" mes "a & b = "+c1; mes "a && b = "+c2; mes "a and b = "+c3; mes "" mes "a | b = "+d1; mes "a || b = "+d2; mes "a or b = "+d3;

==、&&、||などは他言語に慣れた人向けの書き方として用意されている物かと。



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