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


HSPTV!掲示板


未解決 解決 停止 削除要請

2018
0606
南無三六芒星の弾幕を3解決


南無三

リンク

2018/6/6(Wed) 06:55:13|NO.84557

度々お世話になります。
現在
・if、Switch、関数関連の命令を使ってはいけない
・標準命令のみ
の縛りで弾幕シューティングを制作しています。
現状奇数偶数弾などの基本は完成しているのですが、ボス戦での幾何学的な弾幕を作成するのに苦労
しています。
そこでタイトルの通り、六芒星のような形に弾を列に並べる方法を募集します。よろしくお願いします

※上の縛りを遵守してください



この記事に返信する


あらや

リンク

2018/6/6(Wed) 14:42:18|NO.84558

関数が使えないとsin、cos、sqrtなども使えないので少々無理があるんですが、

・六芒星の外側の点6つを繫げると正六角形になる
・正六角形も六芒星も正三角形を組み合わせると描ける
・正三角形を2等分すると、30度・60度・90度の直角三角形になり各辺の比率が1:2:√3になる

これらの性質を利用し、√3は定数にして比率で計算すればできないことはないので
実際にやってみました。

#define root3 1.732050807568877 // 3の平方根 // root3 = 1.732050807568877;としても可 r = 0.0; // 六芒星の外接円の半径(発射台からの距離) ddim center, 2; // 発射台 中心点の座標 center = 320.0, 240.0; cr = 10.0; // 発射台の大きさ(半径) ddim point, 2, 30; // 弾の座標 pr = 5.0; // 弾の大きさ(半径) pspeed = 2.0; // 弾速 loop_counter = 0; // ループカウンタ *main redraw 0; color 255, 255, 255:boxf; gosub *calc_points // 弾座標計算 // 弾 描画 color 255, 0, 0; repeat 30 circle point(0, cnt)+center(0)-pr, point(1, cnt)+center(1)-pr, point(0, cnt)+center(0)+pr, point(1, cnt)+center(1)+pr, 1; loop r = pspeed * loop_counter; // 弾座標更新 // 発射台描画 color 0, 0, 0; circle center(0)-cr, center(1)-cr, center(0)+cr, center(1)+cr, 1; redraw 1; await 17; loop_counter++; // 弾座標更新用カウンタ loop_counter \= 780/pspeed; // 弾が全て画面外に出た時のリセット用 goto *main *calc_points // 正六角形の頂点座標(上から順に時計回り) point(0, 0) = 0.0, -1.0*r; // 正六角形の上の頂点座標 point(0, 1) = r*root3/2.0, -r/2.0; // 正六角形の右上の頂点座標 point(0, 2) = point(0, 1), -point(1, 1); // 正六角形の右下の頂点座標 point(0, 3) = point(0, 0), -point(1, 0); // 正六角形の下の頂点座標 point(0, 4) = -point(0, 1), point(1, 2); // 正六角形の左下の頂点座標 point(0, 5) = point(0, 4), point(1, 1); // 正六角形の左上の頂点座標 // 六芒星の交点(△と▽の交点)座標 p01 = (point(0, 1) - point(0, 5)) / 3.0; // 一時計算用変数 point(0, 6) = p01 + point(0, 5), point(1, 1); // △と▽の上辺の交点座標(左) point(0, 7) = p01*2.0 + point(0, 5), point(1, 1); // △と▽の上辺の交点座標(右) p01 = (point(0, 3) - point(0, 5)) / 3.0; // 一時計算用変数X p02 = (point(1, 3) - point(1, 5)) / 3.0; // 一時計算用変数Y point(0, 8) = p01 + point(0, 5), p02 + point(1, 5); // △と▽の左斜辺の交点座標(上) point(0, 9) = p01*2.0 + point(0, 5), p02*2.0 + point(1, 5); // △と▽の左斜辺の交点座標(下) point(0, 10) = -point(0, 8), point(1, 8); // △と▽の右斜辺の交点座標(上) point(0, 11) = -point(0, 9), point(1, 9); // △と▽の右斜辺の交点座標(下) // 各点の中点の座標 point(0, 12) = (point(0, 0)+point(0, 7)) / 2.0, (point(1, 0)+point(1, 7)) / 2.0; point(0, 13) = (point(0, 7)+point(0, 10)) / 2.0, (point(1, 7)+point(1, 10)) / 2.0; point(0, 14) = (point(0, 10)+point(0, 2)) / 2.0, (point(1, 10)+point(1, 2)) / 2.0; point(0, 15) = (point(0, 2)+point(0, 11)) / 2.0, (point(1, 2)+point(1, 11)) / 2.0; point(0, 16) = (point(0, 11)+point(0, 9)) / 2.0, (point(1, 11)+point(1, 9)) / 2.0; point(0, 17) = (point(0, 9)+point(0, 4)) / 2.0, (point(1, 9)+point(1, 4)) / 2.0; point(0, 18) = (point(0, 4)+point(0, 8)) / 2.0, (point(1, 4)+point(1, 8)) / 2.0; point(0, 19) = (point(0, 8)+point(0, 6)) / 2.0, (point(1, 8)+point(1, 6)) / 2.0; point(0, 20) = (point(0, 6)+point(0, 0)) / 2.0, (point(1, 6)+point(1, 0)) / 2.0; point(0, 21) = (point(0, 1)+point(0, 10)) / 2.0, (point(1, 1)+point(1, 10)) / 2.0; point(0, 22) = (point(0, 10)+point(0, 11)) / 2.0, (point(1, 10)+point(1, 11)) / 2.0; point(0, 23) = (point(0, 11)+point(0, 3)) / 2.0, (point(1, 11)+point(1, 3)) / 2.0; point(0, 24) = (point(0, 3)+point(0, 9)) / 2.0, (point(1, 3)+point(1, 9)) / 2.0; point(0, 25) = (point(0, 9)+point(0, 8)) / 2.0, (point(1, 9)+point(1, 8)) / 2.0; point(0, 26) = (point(0, 8)+point(0, 5)) / 2.0, (point(1, 8)+point(1, 5)) / 2.0; point(0, 27) = (point(0, 5)+point(0, 6)) / 2.0, (point(1, 5)+point(1, 6)) / 2.0; point(0, 28) = (point(0, 6)+point(0, 7)) / 2.0, (point(1, 6)+point(1, 7)) / 2.0; point(0, 29) = (point(0, 7)+point(0, 1)) / 2.0, (point(1, 7)+point(1, 1)) / 2.0; return;

正直手抜きなのでそれぞれ単独で座標計算するとか
精度が微妙だとか個人的に納得できない点は多々ありますが
三角関数を使用せず、1次関数の計算等すらも無しで幾何学的な図形を描くのは
無謀なので誰がやってもこんな感じになる気がします。

もう少しがんばれば多少効率的に組めるような感覚もありますが
いっそ六芒星の基準になる座標をあらかじめ定数データとして
発射した位置から放射線状に広がるようにフレーム毎に
係数を増やして乗算するだけの方がいいかもしれません。



あらや

リンク

2018/6/7(Thu) 16:27:24|NO.84573

修正です。

一点ずつ求めるのは流石に応用しづらいので
少々効率を上げて、ついでに若干精度も上げてみました。

#define root3 1.732050807568877 // 3の平方根 // root3 = 1.732050807568877;としても可 r = 0.0; // 六芒星の外接円の半径(発射台からの距離) ddim center, 2; // 発射台 中心点の座標 center = 320.0, 240.0; cr = 10.0; // 発射台の大きさ(半径) div = 15.0; // 六芒星の辺の分割数(3の倍数にすると形状は綺麗だが、弾が重なる箇所が出来てしまう) ddim point, 2, 6*div; // 弾の座標 pr = 5.0; // 弾の大きさ(半径) pspeed = 2.0; // 弾速 loop_counter = 0; // ループカウンタ *main redraw 0; color 255, 255, 255:boxf; gosub *calc_points // 弾座標計算 // 弾 描画 color 255, 0, 0; repeat 6*div circle point(0, cnt)+center(0)-pr, point(1, cnt)+center(1)-pr, point(0, cnt)+center(0)+pr, point(1, cnt)+center(1)+pr, 1; loop r = pspeed * loop_counter; // 弾座標更新 // 発射台描画 color 0, 0, 0; circle center(0)-cr, center(1)-cr, center(0)+cr, center(1)+cr, 1; redraw 1; await 17; loop_counter++; // 弾座標更新用カウンタ loop_counter \= 780/pspeed; // 弾が全て画面外に出た時のリセット用 goto *main *calc_points // 正三角形の頂点座標 point(0, 0*div) = 0.0, -1.0*r; // 六芒星の上の頂点座標 point(0, 1*div) = r*root3/2.0, r/2.0; // 六芒星の右下の頂点座標 point(0, 2*div) = -r*root3/2.0, r/2.0; // 六芒星の左下の頂点座標 // 六芒星を正三角形2つを組み合わせた図形として考え△を一辺ずつ座標計算する // 1回目のループでは、上の頂点から右下の頂点まで (△の一辺) // 2回目のループでは、右下の頂点から左下の頂点まで (△の一辺) // 3回目のループでは、左下の頂点から上の頂点まで (△の一辺) // それぞれの頂点間の長さをdivで割った数値を足していくだけ // △を計算 repeat 3 idx1 = cnt*div; idx2 = (cnt+1)\3*div; p01 = point(0, idx2) - point(0, idx1); p02 = point(1, idx2) - point(1, idx1); repeat 1*div-1, 1 idx3 = idx1 + cnt; point(0, idx3) = p01*cnt/div + point(0, idx1); point(1, idx3) = p02*cnt/div + point(1, idx1); loop loop // ▽を計算(上のループで求めた△を上下左右反転しているだけ) repeat 3*div point(0, 3*div+cnt) = -point(0, cnt), -point(1, cnt); loop /* divが3の倍数の場合 div/3 と (div*4)+(div*2/3) div*2/3 と (div*5)+(div/3) (div*1)+(div/3) と (div*5)+(div*2/3) (div*1)+(div*2/3) と (div*3)+(div/3) (div*2)+(div/3) と (div*3)+(div*2/3) (div*2)+(div*2/3) と (div*4)+(div/3) これら12ヶ所のインデックスがそれぞれ6点(六芒星内部の正六角形の頂点)で重なることになる */ return;



名無産

リンク

2018/6/10(Sun) 12:50:44|NO.84584

感謝です



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