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


HSPTV!掲示板


未解決 解決 停止 削除要請

2020
0929
kanamaruobaq オブジェクトを並べる方法11解決


kanamaru

リンク

2020/9/29(Tue) 14:20:14|NO.91481

前回のスレッドでスプライトではなくobaqを使うことにしたのですが、
いきなり問題が発生しました。
具体的には
・内部座標が理解できない。
・オブジェクトを並べることができない。
一つ目に関しては、obaqでは内部座標を使っていると思います。
ドキュメントによるとデフォルトでは内部座標の4倍がhspで普段使っている座標になるそうです。
が、以前のスプライトで作ったのと比較しても明らかに違うように見えます。
オブジェクトのサイズも配置座標も4分の一を内部座標として指定してるのに
スプライトで作ってた時と違います。
だったらということで座標を変換する命令を経由すればいいってことで
qcnvaxisを使って内部座標に変換してもやはりおかしいです。
内部座標に関して正しく処理する方法を教えてください。
二つ目に関しては、一つ目が原因な気がしますが、配置座標を(理解している中で)
適切に指定してもきれいに並びません。
上記二つの問題をふまえ、obaqでオブジェクトを隣接して並べる方法を教えてください。
並べる方法は縦も横もお願いします。



この記事に返信する


Drip

リンク

2020/9/29(Tue) 22:21:52|NO.91484

Dripです。
kanamaruさん、こんにちは。

obaqは特殊な座標系を持っており混乱もあるかと思います。
まず座標系の倍率が4倍という設定はqview命令で再設定が可能です。
デフォルトで4が設定されているためこの点は間違いありません。
次に、恐らくqaddpoly命令で四角形を生成し、どうもサイズと位置が合わないと難儀されていらっしゃるのではないでしょうか?
qaddpolyで設定する物体の幅は物体の中心から見た頂点の長さを指定します。
つまり座標系の倍率が4倍の設定では、幅を100と指定した場合、一辺が565ピクセル程度(100/√2*4*2)の四角形が生成されることになります。面倒くさいですね^^;
それらを加味した上で、以下のサンプルを参考にピッタリ敷き詰めるやり方を考察してみてください。

#include "obaq.as" #define debug 1 //1にすると物体に枠を表示して構造がわかりやすい #define sz 40.0 //ブロックの大きさ ※OBAQは最大512個までしか物体を生成できない点に注意してください。 #define zm 4.0 //obaqの倍率。※倍率はqviewで変更可能。このサンプルではこの値に変更して実行する。 #define sp 2.0 //ブロック同士の間隔(0.0でも良いが、ここは2.0くらいに設定しないと惰性等の影響でリンゴに回り込みづらい。) #define bs 10.0 //ボーダーの余白 root2=0.5*sqrt(2) //ルート2の半分(直角二等辺三角形の辺の比率は必ず1:1:√2であるため、指定した一辺の長さを //正方形の中点から見た頂点までの長さに変換する際にこの倍率を利用する。(指定サイズにこれをかけて倍率で割る)) //qaddpolyは図形の対角線の長さ(中心から頂点までの距離)を指定するためこの値が必要になる。 celload dir_exe+"\\hsptv\\hsptv_img.bmp",1 //テクスチャ読み込み celdiv 1,64,64,0,0 //テクスチャ分割 qreset //obaq初期化 qview zm,zm,0,0 //qviewは必ずqresetのあとに実行する。リセットすると倍率もリセットしてしまう。 qgravity 0,0 //重力なしに wx=double(ginfo_winx-bs):wy=double(ginfo_winy-bs) //余白分縮めた画面サイズを実数にしてwx,wyに記憶 qborder -wx/2/zm,-wy/2/zm,wx/2/zm,wy/2/zm //ボーダーを画面サイズ-余白サイズぴったりに配置する repeat wy/(sz+sp):y=cnt //Y方向にブロック配置 repeat wx/(sz+sp):x=cnt //X方向にブロック配置 if x/2!1 | y/2!1:if y/2=1 | x/2=1:continue //十字路を作るので十字路の中心を除く十字路に物を配置しない //一辺がszのサイズの正方形を整列配置(重なり判定は無視して配置) qaddpoly my, 4, ((sz+bs)/2+(sz+sp)*x)/zm,((sz+bs)/2+(sz+sp)*y)/zm,0,root2*sz/zm,root2*sz/zm,0 if x/2=1 & y/2=1:{ //十字路の中心にプレイヤーと押せるブロックを配置する if plr:{ //プレイヤーが定義されていたら押せるブロックを配置する qmat my,mat_spr,1,40 //押せるブロックの模様設定 }else{ //プレイヤーが定義されていなければプレイヤーを配置する plr=my //プレイヤーを定義 qmat my,mat_spr,1,24 //プレイヤーの模様設定 } qtype my,type_bindR //プレイヤーや押せるブロックは回転禁止 }else{ //十字路以外は壁ブロックを配置 qmat my,mat_spr,1,44 //壁の模様 qtype my,type_bind //壁は動かない } qdamper my,0.9,0.5 //高吸振低摩擦にする qinertia my,0.9 //弾みにくくする loop loop *main ; メインループ ; stick ky,15 //カーソルキーで移動 if ky&1:qspeed plr,-0.1 if ky&2:qspeed plr,0,-0.1 if ky&4:qspeed plr,0.1 if ky&8:qspeed plr,0,0.1 redraw 0 //画面の更新を開始 color 0,0,0:boxf //画面をクリア qexec //OBAQによるオブジェクトの更新 qdraw 1-debug //オブジェクトの描画 redraw 1 //画面の更新を終了 await 16 //一定時間待つ goto *main
ところで、ご質問の意図からゲームの舞台?をマップチップのように配置して管理されようとしているように見えるのですが、obaqでは512個までしか物体を生成できません。
従いまして、マップチップのように大量に物体を配置すると僅か23×23マスの壁を生成しただけで限界を突破してしまいます。
この点には充分注意した上で作品を設計されてください。(大きく複雑なマップの場合、自作の多角形オブジェクトを配置するなどして物体の数を減らす工夫が必要になります。)
ちなみに、今回のサンプルではブロックの幅を20くらいに設定すると途中で限界を突破してブロックの生成が途中で失敗します。



さか

リンク

2020/9/29(Tue) 22:42:14|NO.91485

前回のスレッドに書いたのですが気づかれないかもしれないのでこちらにも。
esでやるならこんな感じです。アニメーションもつけてみてます。


#include "hsp3dish.as" screen 0,640,480 ; スクリーン初期化 es_ini ; スプライトを初期化 buffer 3 picload dir_exe+"\\hsptv\\hsptv_img.png" ; hspインストールフォルダ\hsptvの下の画像ファイル es_size 64, 64, 70 es_pat 0, 0, 192, 3 ; my1 es_pat 1, 64, 192, 3 ; my2 es_link 1,0 es_pat 2, 0, 320 es_pat 3, 64, 320 gsel 0 ; 初期設定 x = 320: y = 200 es_set 0, x, y, 0 ; スプライトを配置 x1 = 200: y1 = y es_set 1, x1, y1, 2 ; スプライトを配置 x2 = 450: y2 = y es_set 2, x2, y2, 3 ; スプライトを配置 *@ redraw 0 color 0, 0, 0: boxf stick key,15 :title ""+key vx = 0: vy = 0 if key&1: vx = -10 if key&4: vx = 10 if key&8: vy = 10 if key&2: vy = -10 ;衝突チェック es_pos 0, x+vx, y+vy es_check chk,0 ; リンゴの場合、押す if chk == 1: x1 += vx: y1 += vy ; どくろリンゴと衝突の場合、止まる if chk == 2: vx = 0: vy = 0 x += vx: y += vy es_pos 0, x, y es_pos 1, x1, y1 es_pos 2, x2, y2 es_draw ; スプライトを描画 redraw 1 wait 10 goto *@b



kanamaru

リンク

2020/9/29(Tue) 23:53:35|NO.91488

Dripさん、前のスレッドに続いてありがとうございます。
そういえば多角形扱えるんだから単純な縦横じゃないですよね。
色々変更して無事とりあえず前回のスレッドの時の疑問が解決したくらいまで実装できました。
ただ、またもや問題が、しかもDripさんのプログラムで発生してないところを見ると
説明が困難な気がします。
本当は手元で作っているプログラムを投稿するのが一番なんでしょうが
既存ゲームを再現してる関係で見た目もルールも思いっきりおんなじなんですよね。
外部で発表しないので個人的に作る分にはいいんでしょうが、
ここに投稿するのはちょっと問題な気がします。
で、頑張って発生している問題を説明すると、
どうやらオブジェクトによっては正方形じゃない気がします。
表示している枠を見た感じオブジェクトの下の辺の左半分が少し下にあるように見えます。
(該当オブジェクトは複数あります)
おかげで衝突がそのオブジェクトだけ想定と違くなっています。
一応毎回同じオブジェクトで見られる現象なので
何らかの発生条件はあるんでしょうが現状不明です。
スプライトのサイズも使っている画像のサイズも問題ないことは確認しました。
こんな曖昧な説明ですが、何か原因に心当たりありますか?
一応使う画像を著作権問題ない画像に変えてスクショをとって
明日の朝にでも投稿します。



Drip

リンク

2020/9/30(Wed) 00:50:09|NO.91490

kanamaruさん

kanamaruさんの仰る四角形の一辺が斜めになって見える現象は先ほどの私のサンプルでも確認できます。
私のサンプルのタイルマップの上の列の辺をよく見ますと、下の辺(白いライン)が若干斜めになっているのがわかると思います。
これは図形の頂点を形成する際にπの2倍を360度として、それを多角形分で割った角度でそれぞれの頂点を配置した結果、小数点誤差の問題で見かけ上ラインが1ドット分斜めにずれて表示されることがあります。

//四角形の一辺が斜めに見えるサンプル #include "obaq.as" qreset ; OBAQの初期化 qaddpoly my, 4, 30,20,0,sqrt(2)*10,sqrt(2)*10 qaddpoly my, 4, 130,20,0,sqrt(2)*10,sqrt(2)*10 qgravity 0,0 repeat redraw 0:color:boxf qexec:qdraw redraw 1:await 30 loop
しかし通常の場合、斜めなのは線の見かけだけで、テクスチャのみで物体を描画した場合まで形状が斜めには見えないはずです。
私のサンプルも斜めに見えるブロックにキャラクターをくっつけてスライドさせても、特に引っかかることもないかと思います。

>おかげで衝突がそのオブジェクトだけ想定と違くなっています。

これはちょっと私にはわからないため臆測に過ぎないのですが、もし本当に物体が斜めになってしまいスライドさせた物体が引っかかってしまうような場合、うまく動作するように摩擦や惰性の値などを調整する必要があるかもしれません。
まずは本当に小数点誤差が問題の原因なのか、それともご自分のスクリプトに原因があるのかよく見極める必要があるかと思います。

また前のスレッドでも書きましたように、OBAQではある程度の判定の雑さを許容する必要があります。
図形同士を並べるとひっかかってしまい、それがどうしても許容できない状況の場合、物体を2つ並べずに1つの塊にした多角形を配置したり、摩擦や惰性の値を調整するなどして、問題を回避していく必要が出てくるかと思います。
頑張ってみてください。



Drip

リンク

2020/9/30(Wed) 01:41:48|NO.91491

上記に付け加えまして、厳密なところでは以下のようなブロックの判定順序も考える必要があるかもしれません。
次の例では生成順序を変えたために右の列が左の列と異なる結果で動作します。

#define junjoGyakuten 0 //これを1にして実行すると? #include "obaq.as" qreset repeat 5 qaddpoly my, 4, 80,20+cnt*16,0 //左の列は上から下に生成 if junjoGyakuten:{ qaddpoly my, 4, 120,20+(4-cnt)*16,0 //右の列を下から上に生成 }else{ qaddpoly my, 4, 120,20+cnt*16,0 //右の列を上から下に生成 } loop repeat redraw 0:color:boxf qexec:qdraw redraw 1:await 30 loop
また次の例では全く同じ順序で生成しているにもかかわらず2列の結果が異なります。

#include "obaq.as" qreset repeat 5 qaddpoly my, 4, 40,20+cnt*16,0 //左の列 qaddpoly my, 4, 120,20+cnt*16,0 //右の列 loop repeat redraw 0:color:boxf qexec:qdraw redraw 1:await 30 loop
これらが問題となるような厳格な状況では、OBAQで全てを運用するのは難しいかもしれませんね^^;



kanamaru

リンク

2020/9/30(Wed) 07:22:19|NO.91494

またもや多角形を描画しているってことをわすれてました。
確かに多角形を描画するならそうなりそうです。
また、Dripさんが提示したプログラムを実行して、
おそらく同じ現象だということを確認しました。
Dripさん、毎回ありがとうございます。
厳格というより、衝突したときに引っ掛かるのか
目視が可能なほどオブジェクトが上下するので違和感があるんです。
ということで、この後試してみますが、
この問題を解決できる方法の心当たりができました。
今回が限定的な状況なので出来る方法ですが。
Dripさんが原因を突き止めてくれたおかげです。
ありがとうございました。



kanamaru

リンク

2020/9/30(Wed) 11:05:37|NO.91496

思い浮かんだ解決策を適用した結果ほとんどうまくいきました。
僕が使った(解決しなかったけど)解決策というのは、
以下の自作命令をqaddpolyの代わりに使うことです。

goto *j #deffunc qaddbox var _obj,double _x,double _y,double _w,double _h,int _c,int _m,int _e,int _l ddim _vtex,10 _vtex = -1.0,-1.0,-1.0,1.0,1.0,1.0,1.0,-1.0,-1.0,-1.0 qaddmodel _obj,_vtex,-1,_x,_y,0.0,_w,_h,_c,_m,_e,_l return *j
goto文はなんかないとエラーが出るみたいなので追加しています。
モジュール空間に分離できればいいですけど
そうするとqaddmodelが使えないんです。
引数が省略されないことと大きさの解釈が通常と違うので気を付けてください。
辺が斜めに見えるサンプルで使うと

//四角形の一辺が斜めに見えるサンプル #include "obaq.as" goto *j #deffunc qaddbox var _obj,double _x,double _y,double _w,double _h,int _c,int _m,int _e,int _l ddim _vtex,10 _vtex = -1.0,-1.0,-1.0,1.0,1.0,1.0,1.0,-1.0,-1.0,-1.0 qaddmodel _obj,_vtex,-1,_x,_y,0.0,_w,_h,_c,_m,_e,_l return *j qreset ; OBAQの初期化 qaddpoly my, 4, 30,20,0,sqrt(2)*10,sqrt(2)*10 //qaddpoly my, 4, 130,20,0,sqrt(2)*10,sqrt(2)*10 qaddbox my,130,20,10,10 qgravity 0,0 repeat redraw 0:color:boxf qexec:qdraw redraw 1:await 30 loop
こうなります。
右の四角形が辺が斜めになってないのが確認できると思います。
しかしそれでも解決はしていませんでした。
いくつか試してみたところ、思わぬ原因がわかりました。
壁にぶつかったとき微妙に戻るじゃないですか。
その結果、実際には壁ギリギリを進んでいると思っていても少しだけ壁より離れていたようです
摩擦なのかそのずれを無理やり押してたからオブジェクトが動いたみたいです。
その証拠に、方向キーを押しっぱなしにして壁に押し付けながら進んだら
壁オブジェクトが動かずに進むことができました。
壁にぶつかったときに微妙に戻るのをなくす方法ってありますか?



kanamaru

リンク

2020/9/30(Wed) 11:23:49|NO.91497

すいません訂正です。
壁オブジェクトが動かずに進むことができました。
じゃなくて
押すオブジェクトが動かずに進むことができました。
ついでに説明がわかりにくいと思ったので補足しておくと、
状況としては壁オブジェクトと押すオブジェクトの間を進むと
押すオブジェクトが動くという話をしていました。



kanamaru

リンク

2020/9/30(Wed) 13:05:27|NO.91498

何度もすいません。
どうも検証を重ねると状況は複雑みたいです。
壁オブジェクトに下からぶつかるか右からぶつかる場合は大丈夫みたいです
(むしろ押し付けるとのめりこむみたいです)
しかし上からぶつかる場合と左からぶつかる場合は違う挙動のようです。
何ピクセルかはわかりませんか手前になるようです。
で、押し付ける(壁に向かってキーを押し続ける)とぴったり隣接する。
上からぶつかったときと左からぶつかったときの挙動を
下からぶつかったときと右からぶつかったときと同じ挙動にすることはできますか?



Drip

リンク

2020/9/30(Wed) 20:02:40|NO.91499

kanamaruさん

>壁にぶつかったときに微妙に戻るのをなくす方法ってありますか?

私のリンゴを押すマップ移動のサンプルでは

qinertia my,0.9 //弾みにくくする
という箇所で物体の跳ね返りを抑えています。この行を消すと物体が跳ね回ってしまいます。
この値を0.99とかにすると私のサンプルもkanamaruさんの仰るような跳ね返り状態になると思います。
この値は非常にピーキーな値のようで、少しいじっただけで一気に練り飴の中のような世界になったり、逆に世界中がトランポリンになったように感じられるかもしれません。
摩擦を制御するqdamper命令や重みを制御するqweight命令も合わせてうまく調整し、好みの質量感を表現してみてください。
なお、これらの値を異常な値に設定すると物体が別の物体に吸収されたりすり抜けたり、暴走することもobaqではよくあります。
また物体に余白を設けることも大切です。obaqでは若干物体が物体にめり込み、元に戻ろうとする力が働くため、どうしても完全に跳ね返りを抑止することが難しいです。
私のサンプルでは標準で1チップあたり2ピクセルの隙間を設けてキャラクターを動きやすくしています。
繰り返し書いておりますが、OBAQを使う以上、ある程度の判定の雑さは許容しなければならないことを胸に留めてください。



kanamaru

リンク

2020/9/30(Wed) 20:11:35|NO.91500

なるほど。わかりました。
色々調整してみます。



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