|
|
2019/3/30(Sat) 10:30:21|NO.86996
こんにちは
昔のスクリーンセーバーの宇宙飛行(名前忘れました)のように
疑似3D空間を星(白の点)が近づいてきて、あたかも等速で飛んでいるような
表現をしたいのですが、モジュールを使わない場合、どのように星の位置を
計算すればよいでしょうか?
距離に応じて白い点の大きさと濃淡を変化させて
画面中央はゆっくり、画面端の方は早く見切れていくイメージです。
|
|
2019/3/30(Sat) 19:45:04|NO.87001
>>画面中央はゆっくり、画面端の方は早く見切れていくイメージです。
極簡単な例は
repeat 200
cls
R=powf(cnt,1.1)
S=3.14/180
pos 320+R*sin( 0.0*S),240+R*cos( 0.0*S) : mes "."
pos 320+R*sin( 45.0*S),240+R*cos( 45.0*S) : mes "."
pos 320+R*sin( 90.0*S),240+R*cos( 90.0*S) : mes "."
pos 320+R*sin(135.0*S),240+R*cos(135.0*S) : mes "."
pos 320+R*sin(180.0*S),240+R*cos(180.0*S) : mes "."
pos 320+R*sin(225.0*S),240+R*cos(225.0*S) : mes "."
pos 320+R*sin(270.0*S),240+R*cos(270.0*S) : mes "."
pos 320+R*sin(315.0*S),240+R*cos(315.0*S) : mes "."
R=powf(cnt,1.2)
S=22.5*3.14/180
pos 320+R*sin( 0.0*S),240+R*cos( 0.0*S) : mes "."
pos 320+R*sin( 45.0*S),240+R*cos( 45.0*S) : mes "."
pos 320+R*sin( 90.0*S),240+R*cos( 90.0*S) : mes "."
pos 320+R*sin(135.0*S),240+R*cos(135.0*S) : mes "."
pos 320+R*sin(180.0*S),240+R*cos(180.0*S) : mes "."
pos 320+R*sin(225.0*S),240+R*cos(225.0*S) : mes "."
pos 320+R*sin(270.0*S),240+R*cos(270.0*S) : mes "."
pos 320+R*sin(315.0*S),240+R*cos(315.0*S) : mes "."
wait 1
loop
基本的には三角関数と二次方程式の応用です。
相対的に、止まっている宇宙船に星が近づいてくるとすると
向かって来る速度の水平成分をm[m/s]、垂直成分をn[m/s]
宇宙船との初期距離p[m]
t秒後は
水平距離X=p-mt[m]
垂直距離Y=nt[m]
実際の距離Rは R^2=X^2+Y^2
となります。
見かけの大きさは星の直径f[m]
a=2tan(f/2R)
です。
計算的には上記の様に成りますが、これはあくまで
「極遅い速度で撮影した動画を、超高速で再生した」
場合で、実際には全く別の見え方になります。
| |
|
2019/3/30(Sat) 21:19:33|NO.87002
昔よくあった疑似3Dのやつですかね?
こんな感じの。
#const OBJ_MAX 1024 // 星の最大数
#const CX 320 // 画面中心X
#const CY 240 // 画面中心Y
#const CZ 1024 // 画面奥行き
#const SIZE 16 // 星のサイズ
dim x, OBJ_MAX // 星の位置X
dim y, OBJ_MAX // 星の位置Y
dim z, OBJ_MAX // 星の位置Z
dim f, OBJ_MAX // 星の使用フラグ
dim px, OBJ_MAX // 星の描画位置X
dim py, OBJ_MAX // 星の描画位置Y
dim ps, OBJ_MAX // 星の描画時のサイズ
*main
// 星の生成
repeat OBJ_MAX
if (f(cnt) == 1):continue
f(cnt) = 1
x(cnt) = rnd(640) - CX
y(cnt) = rnd(480) - CY
z(cnt) = CZ
break;
loop
// 星の更新
repeat OBJ_MAX
if (f(cnt) == 0):continue
z(cnt)--
if (z(cnt) <= 0) {
f(cnt) = 0
continue
}
// 奥行きからサイズを計算
ps(cnt) = (SIZE * (CZ - z(cnt))) / CZ
// 小さすぎると表示されなくなるので最低限の大きさにする
if (ps(cnt) < 2):ps(cnt) = 2
// 奥行きから画面表示位置を計算
tx = ((CZ * x(cnt)) / z(cnt))
ty = ((CZ * y(cnt)) / z(cnt))
px(cnt) = tx - ps(cnt) + CX
py(cnt) = ty - ps(cnt) + CY
loop
// 描画
redraw 0
color 0, 0, 0
boxf
color 255, 255, 255
repeat OBJ_MAX
if (f(cnt) == 0):continue
circle px(cnt), py(cnt), px(cnt) + ps(cnt), py(cnt) + ps(cnt), 1
loop
redraw 1
await (1000 / 60)
goto *main
| |
|
2019/3/30(Sat) 22:30:24|NO.87003
自分もちょっと作ってみました。
MAX=100
dim x, MAX
dim y, MAX
dim vx, MAX
dim vy, MAX
dim flg, MAX
randomize int( gettime( 7 ) )
bb = 100
ii = 0
repeat
redraw 0: color 0,0,0: boxf: color 255,255,255
repeat MAX
if flg( cnt ) == 0{
x( cnt ) = rnd( ginfo_winx ) * bb: y( cnt ) = rnd( ginfo_winy ) * bb
vx( cnt ) = x( cnt )/ bb - ginfo_winx / 2: vy( cnt ) = y( cnt )/ bb - ginfo_winy / 2
flg( cnt ) = 1
}
x( cnt ) + = vx( cnt ): y( cnt ) + = vy( cnt )
pos x( cnt ) / bb, y( cnt ) / bb: mes "."
if x( cnt ) < 0 or x( cnt ) > ginfo_winx * bb or y( cnt ) < 0 or y( cnt ) > ginfo_winy * bb: flg( cnt ) = 0
loop
redraw 1
wait 0
loop
|
|
2019/3/30(Sat) 23:39:14|NO.87004
作ってみたはいいが、星ごとの速度の違い(速い星、遅い星、とても遅い星)を
取り入れようとしたところで力尽きたのを貼っておきます。
//以下のconstの数値をいじることで、星の数や速さ、最大の大きさを調整できます
#const wx 1000 //画面の横サイズ
#const wy 800 //画面の縦サイズ
#const stars 60 //星の数
#const spd 0.15 //初速度(実数)
#const w_time 16 //await文での待ち時間
#const freq 24 //星のサイズを大きくする頻度
#const conce 20 //星が出現した時の色の濃さ
screen 0,wx,wy,1 //負荷低減のためパレットモードで
repeat 100 : a=cnt*(255-conce)/99+conce : palette cnt+1,a,a,a : loop //パレットの作成。100に近いほど白くなる
palette 0,0,0,0,1
dim times,stars //星が出現してからどのくらい時間が経ったか
dim flag,stars //星が出現しているかどうか
ddim rad,stars //星が飛ぶ角度
cent_x=wx/2 : cent_y=wy/2 //中心座標
move_max=int(sqrt(wx*wx/4+wy*wy/4))+1 //中心からの最大飛距離
zoom_t=move_max/freq //この距離だけ進むごとに星のサイズを大きくする
add=limit(int(sqrt(double(move_max)/spd))/stars,1,65535) //時間がこれだけ進むごとに星を追加
stock_n=stars //まだ登場していない星の数
dim stock,stars : repeat stars : stock(cnt)=cnt : loop //登場していない星の星番号
randomize
repeat
redraw 0
palcolor 0 : boxf
//星の追加
if (cnt\add=0)&(stock_n>0) {
a=stock(stock_n-1) : stock_n--
flag(a)=1
rad(a)=deg2rad(rnd(360))
times(a)=0
}
repeat stars
if flag(cnt)=0 : continue
move=double(times(cnt)*times(cnt))*spd //中央から飛んだ距離 時間の2乗に比例
x=int(cos(rad(cnt))*move)+cent_x //x座標を求める
y=int(sin(rad(cnt))*move)+cent_y //y座標を求める
size=times(cnt)/zoom_t+1 //表示する大きさ
if (x<0-size)|(x>wx+size)|(y<0-size)|(y>wy+size) {
//画面外に出た場合は星を消す
stock(stock_n)=cnt : stock_n++
continue
}
palcolor int(move)*99/move_max+1 //進むほど色が白に近くなる
boxf x-size,y-size,x+size-1,y+size-1
times(cnt)++
loop
redraw 1
await w_time
loop
| |
|
2019/3/31(Sun) 09:55:54|NO.87006
うお〜っ4つとも凄い。色々な方法があるのですね。
どうしたらこういうの思いつかれるのでしょう。
以下、自分の解釈と感想です。
間違っていましたらご指摘ください。
KAさんのは、考え方の参考、角度と距離から表示位置を決めると、式も詳しく示して頂いて、オーなるほどと納得です、が、自分で思い付く気がしません。
法貴優雅さんのは、奥行が見え方を支配すると、コードを見せてもらえれば…なるほど凄い、うーん、やはり自分で思い付く気が全くしません。
さかさんのは、初期位置で初速を固定するだけでそれっぽく見えるよと…なぜこれでそれっぽく見えてしまうのか…謎です、不思議です、凄いです。わかりません。
沢渡さんのは、角度を決めて、時間と速度から計算で座標を求められていると、こういう式はスッと出てくるのでしょうか、うーん、やはり謎です、凄いです。
皆様ありがとうございます。ご提示頂いたコードはバリエーションも豊富で、
ちょっと感動です。環境や、負荷に合わせて使い分けられるよう精進したいです。
|
|
2019/3/31(Sun) 15:54:46|NO.87009
解決済みですが自分も作ったので…
randomize
screenW = ginfo_sx
screenH = ginfo_sy
centerX = screenW / 2
centerY = screenH / 2
num = 200
ddim posx, num
ddim posy, num
ddim size, num
repeat num
new cnt
loop
*mainLoop
redraw 0
color
boxf
repeat num
; サイズ・座標の更新
size(cnt) *= 1.01
aj = size(cnt) / 500 ; 加速感・立体感の味付け
posx(cnt) *= 1.002 + aj
posy(cnt) *= 1.002 + aj
; 仮想座標からスクリーン座標に変換
x = posx(cnt) * centerX + centerX
y = posy(cnt) * centerY + centerY
if size(cnt) > 20 || x < 0 || x > screenW || y < 0 || y > screenH {
new cnt
}
hsvcolor 0, 0, limit(size(cnt) * 120, 0, 255)
if (size(cnt) < 2) {
pset x, y
} else {
grect x, y, 0, size(cnt), size(cnt)
}
loop
redraw 1
await 15
goto *mainLoop
#deffunc new int i
; -1 〜 1 の仮想座標に設置
posx(i) = 0.001 * rnd(2000) - 1
posy(i) = 0.001 * rnd(2000) - 1
size(i) = 0.5
return
ありきたりですが数学や色んなコードに触れることで引き出しが増えて思い付くようになると思います。
|
|