Flashなどでありそうな3Dの画像ビューア。のサンプル。
マウスのホイールに連動して回転します。#include "d3m.hsp"
#include "hspmath.as"
#const TILE_NUM 16
#const SHIFT_TURN 5
#const BUFFER_WIDTH 200
#const BUFFER_HEIGHT 200
// タイルを表示するための配列変数
tile_x = 100, 300, 300, 100
tile_y = 0, 0, 0, 0
tile_z = 200, 200, 0, 0
// タイル用のバッファを作成
repeat TILE_NUM, 1
buffer cnt, BUFFER_WIDTH, BUFFER_HEIGHT
color , 255 : boxf
color 255, 255, 255
font msgothic, 32, font_bold
mes cnt
loop
// メイン画面の初期化・カメラ設定
screen 0, 240, 200, screen_normal
title "ホイールで回転"
d3setcam -250,-300,100, 250,0,100
// 各種初期化作業
gmode GMODE_ALPHA, , , 128
theta_shift = 0.0 // タイルの回転量
theta_add = 0.0 // タイルの角速度
moving = 0 // 回転中フラグ
need_to_draw = 1 // 描画フラグ
// ★メインループ
*main
gosub *move
gosub *draw
wait 5
goto *main
// 移動計算
*move
mw = mousew
if moving > 0 {
// 移動中
moving--
theta_shift += theta_add
} else : if mw != 0 {
// 静止中かつホイールが動いたとき
moving = SHIFT_TURN // SHIFT_TURN回動く
need_to_draw = 1 // 描画フラグON
// 角速度を決定
theta_add = M_PI * 2.0 * sgn(mw) / SHIFT_TURN / TILE_NUM
}
return
// 描画処理
*draw
if need_to_draw == 0 : return
if moving == 0 : need_to_draw = 0
redraw 0
color : boxf
vect_x = cos(theta_shift)
vect_y = sin(theta_shift)
// 2.0 * M_PI / TILE_NUMだけ角度(位置)を変えながら、タイルをTILE_NUM個描画
repeat TILE_NUM
d3rotate vect_x, vect_y, vect_x, vect_y, 2.0 * M_PI / TILE_NUM
d3setlocal 0,0,0, vect_x,vect_y,0, -vect_y,vect_x,0, 0,0,1
d3texture tile_x, tile_y, tile_z, cnt + 1, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT, 1
loop
redraw 1
return
2007年12月20日木曜日
3D画像ビューア サンプル
2007年10月2日火曜日
俯瞰型RPGマップの描画 2
前回のスクリプトにカメラの移動とキャラクタの移動・ジャンプを追加しました。マップチップの明るさは距離に応じた変化に限定しています。
ここまでくるとRPGというよりはアクションに近いものがありますね。
カメラの位置に合わせてカーソルキーで移動する方向を変化させる処理や、ビルボードのようにキャラクタを常に手前を向ける処理など、三角関数を多用しているので、今回のスクリプトはさすがに読みづらいと思います。d3setlocal命令によって多少は読みやすくなっていますが……。興味のある方はぜひ式を解いてみてください。// カーソルキーでキャラクタの移動
// Ctrl同時押しでカメラの移動(回転)
// Spaceでジャンプ
#include "d3m.hsp"
#include "hspmath.as"
#const CELL_SIZE 100 // d3m上のマップチップサイズ
#const IMG_SIZE 64 // bmpのマップチップサイズ
#const CAM_DIST 500
#const CHAR_SPEED 15
#const MAP_WIDTH 18
#const MAP_HEIGHT 15
// マップチップのロード
buffer 1 : picload dir_exe + "/sample/game/testchr.bmp"
// 影用の画像を用意する
color : boxf IMG_SIZE * 3, 0, IMG_SIZE * 4, IMG_SIZE
color 255,255,255 : circle IMG_SIZE * 3, 0, IMG_SIZE * 4, IMG_SIZE, 1
gsel 0
// 変数の初期化
cam_theta = M_PI * 2 / 5 // カメラの角度
cam_phi = -M_PI / 2
char_x = 0.0 // キャラクタの位置
char_y = 0.0
char_z = 0.0
char_vz = 0.0 // キャラクタの速度
// マップ作成
dim map, MAP_WIDTH, MAP_HEIGHT
repeat length2( map )
y = cnt
repeat length( map )
map( cnt, y ) = rnd( 3 )
loop
loop
gosub *draw
*main
stick keys, 15 + 64
gosub *move
if ( is_jumping ) | ( ( keys & 15 ) > 0 ) : gosub *draw
wait 3
goto *main
*move
if ( keys >> 4 & 1 ) & ( is_jumping == 0 ) {
char_vz = 20.0 // ジャンプ開始
is_jumping = 1 // ジャンプ中フラグをON
}
char_vz -= 2.0 // 重力による加速
char_z += char_vz // Z方向の移動
if char_z < 0.0 {
// 着地時の演算
char_z = 0.0
char_vz = 0.0
is_jumping = 0
}
if keys & 64 {
// ctrl同時押し…カメラの移動
cam_theta = limitf( cam_theta + 0.05 * ((keys >> 3 & 1) - (keys >> 1 & 1)), 0.01, M_PI / 2 - 0.01 )
cam_phi += 0.05 * ((keys >> 2 & 1) - (keys & 1))
} else {
// ctrlを押さない…キャラクタの移動
keys_x = (keys >> 2 & 1) - (keys & 1)
keys_y = (keys >> 3 & 1) - (keys >> 1 & 1)
char_x = limitf( char_x - ( sin( cam_phi ) * keys_x - cos( cam_phi ) * keys_y ) * CHAR_SPEED, -MAP_WIDTH/2*CELL_SIZE, (MAP_WIDTH-1)/2*CELL_SIZE)
char_y = limitf( char_y + ( cos( cam_phi ) * keys_x + sin( cam_phi ) * keys_y ) * CHAR_SPEED, -MAP_HEIGHT/2*CELL_SIZE, (MAP_HEIGHT-1)/2*CELL_SIZE)
}
return
*draw
// カメラの設定
d3setcam cos(cam_phi)*sin(cam_theta)*CAM_DIST + char_x, sin(cam_phi)*sin(cam_theta)*CAM_DIST + char_y, cos(cam_theta)*CAM_DIST, char_x, char_y, 0
redraw 0
color : boxf
gz = 0, 0, 0, 0 // d3texture用の配列
repeat MAP_WIDTH, -MAP_WIDTH/2 : x = cnt
repeat MAP_HEIGHT, -MAP_HEIGHT/2 : y = cnt
dx = ( x * CELL_SIZE - char_x ) / CELL_SIZE
dy = ( y * CELL_SIZE - char_y ) / CELL_SIZE
gmode GMODE_ALPHA, , , 255.0 / pow( dx * dx + dy * dy + 1, 0.25 )
// d3texture用の配列を準備
gx( 0 ) = x * CELL_SIZE - CELL_SIZE / 2, x * CELL_SIZE + CELL_SIZE / 2
gx( 2 ) = gx( 1 ), gx( 0 )
gy( 0 ) = y * CELL_SIZE + CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
gy( 2 ) = y * CELL_SIZE - CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
d3texture gx, gy, gz, 1, IMG_SIZE * map( x + MAP_WIDTH/2, y + MAP_HEIGHT/2 ), 0, IMG_SIZE, IMG_SIZE
loop
loop
d3setlocal char_x, char_y, 0, sin(cam_phi),cos(cam_phi),0,-cos(cam_phi),sin(cam_phi),0,0,0,1
// 影を描画
gmode GMODE_SUB,,,32
gx( 0 ) = -CELL_SIZE / 2, CELL_SIZE / 2
gx( 2 ) = gx( 1 ), gx( 0 )
gy( 0 ) = CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
gy( 2 ) = -CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
gz( 0 ) = 0, 0, 0, 0
d3texture gx, gy, gz, 1, IMG_SIZE * 3, 0, IMG_SIZE, IMG_SIZE
// キャラクターを描画
gmode GMODE_RGB0
gy( 0 ) = 0, 0, 0, 0
gz( 0 ) = CELL_SIZE + char_z : gz( 1 ) = gz( 0 )
gz( 2 ) = int( char_z ) : gz( 3 ) = gz( 2 )
d3texture gx, gy, gz, 1, IMG_SIZE * 1, IMG_SIZE, IMG_SIZE, IMG_SIZE
redraw 1
return
俯瞰型RPGマップの描画
RPG関連のスクリプトを書こうと思い立ち、作成。普通のマップじゃつまらないので3Dにしてみました。
drawmodeが1の時の明るさの計算は、CodeZine: 3Dモデルを表示するJavaアプレットの作成を参考としています。
障害物のあるマップで視野を求めるで使った視野計算を合わせれば、よりそれっぽくなりそうです。
少々単純すぎるうえに用途が限られるので、開発wikiには投げずにここへ置いときます。#include "d3m.hsp"
#const CELL_SIZE 100 // d3m上のマップチップサイズ
#const IMG_SIZE 64 // bmpのマップチップサイズ
#const CAM_X 0 // カメラ位置(45°手前から俯瞰)
#const CAM_Y -400
#const CAM_Z 400
#define ctype pow(%1,%2) expf(logf(%1)*(%2)) // x^y
// マップチップのロード
buffer 1 : picload dir_exe + "/sample/game/testchr.bmp"
// カメラの設定
gsel 0
d3setcam CAM_X, CAM_Y, CAM_Z, 0, 0, 0
// 変数の初期化
gz = 0, 0, 0, 0 // d3texture用の配列
ch = CAM_Z // CH = カメラの高さ
// マップ作成
dim map, 20, 20
repeat length2( map )
y = cnt
repeat length( map )
map( cnt, y ) = rnd( 3 )
loop
loop
title "クリックで描画モード変更"
onclick gosub *change_drawmode
gosub *draw
stop
*draw
redraw 0
color : boxf
for x, -10, 10
for y, -10, 10
// マップチップの明るさを計算
switch drawmode
case 0 // 均等描画(どのマップチップも同じ明るさで描画)
c = 255
swbreak
case 1 // 光の反射を考慮(45°手前から俯瞰するとして最適化済み)
// カメラの位置を点C、カメラの位置からXY平面におろした垂線の足を点H、
// マップチップの中心を点B、マップチップの中心からY軸におろした垂線の足を点A、
// XY平面上の原点を点Oとする。
// このとき、マップの中心が最も明るいという条件(すなわち光が45°奥から入射するという条件)を課すと、
// マップの明るさは cos( ∠COH - ∠CAH ) * cos( ∠BCA ) で決定される。
ah = y * CELL_SIZE - CAM_Y // AH
ab = x * CELL_SIZE // AB
cb = sqrt( ab * ab + ah * ah + ch * ch ) // CB
c = int( double( ah + ch ) / ( sqrt( 2.0 ) * cb ) * 255 ) // = cos( ∠COH - ∠CAH ) * cos( ∠BCA ) * 255
swbreak
case 2 // 距離に応じて変化(遠ければ遠いほど暗くなる)
c = int( 255.0 / pow( x * x + y * y + 1, 0.2 ) ) // 距離に反比例させると暗すぎたので0.2乗で調整
swbreak
swend
gmode GMODE_ALPHA, , , c
// d3texture用の配列を準備
gx( 0 ) = x * CELL_SIZE - CELL_SIZE / 2, x * CELL_SIZE + CELL_SIZE / 2
gx( 2 ) = gx( 1 ), gx( 0 )
gy( 0 ) = y * CELL_SIZE + CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
gy( 2 ) = y * CELL_SIZE - CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
d3texture gx, gy, gz, 1, IMG_SIZE * map( x + 10, y + 10 ), 0, IMG_SIZE, IMG_SIZE
next
next
redraw 1
return
*change_drawmode
drawmode = ( drawmode + 1 ) \ 3
switch drawmode
case 0 : title "均等描画" : swbreak
case 1 : title "光の反射を考慮" : swbreak
case 2 : title "距離に応じて変化" : swbreak
swend
gosub *draw
return
2007年7月27日金曜日
円柱のHSV色空間
#include "d3m.hsp"
#include "hspda.as"
#const H_MAX 12
#const S_MAX 4
#const V_MAX 7
#const PANEL_MAX H_MAX * S_MAX * V_MAX
#const PANEL_SIZE 150 // パネル一辺の長さ
#const PANEL_DIST 200 // 同じ角度上のパネル同士の距離(左下の座標の間)
#const OBSERVER_R 2000 // 観測者の中心からの距離
#const double PI 3.1415
#const double ANG_SPEED 0.04 // 観測者の角速度
ct = 0.0
d3setcam OBSERVER_R, 0, V_MAX * 100, 0, 0, V_MAX * 100
*init
dim panel_h, PANEL_MAX : dim panel_s, PANEL_MAX : dim panel_v, PANEL_MAX // 色(HSV指定)
dim panel_r, PANEL_MAX : ddim panel_t, PANEL_MAX : dim panel_z, PANEL_MAX // パネルの位置 円柱座標系(パネルの左下の座標)
ddim panel_far, PANEL_MAX // 奥行き
repeat H_MAX : cnt1 = cnt
h = 191 * cnt / H_MAX // HSV の H
t = PI * 2.0 * cnt / H_MAX // 角度
repeat S_MAX : cnt2 = cnt
s = 256 * cnt / S_MAX // HSV の S
r = cnt * PANEL_DIST + PANEL_DIST / 2 // 中心からの距離
repeat V_MAX
v = 256 * cnt / V_MAX // HSV の V
i = cnt1 * S_MAX * V_MAX + cnt2 * V_MAX + cnt
panel_h( i ) = h : panel_s( i ) = s : panel_v( i ) = v
panel_r( i ) = r : panel_t( i ) = t : panel_z( i ) = cnt * PANEL_DIST
loop
loop
loop
observer_t = 0.0
*main
gosub *calc
gosub *draw
wait 2
goto *main
*calc
// 観測者の回転
observer_t += ANG_SPEED
if ( PI * 2.0 < observer_t ) : observer_t -= PI * 2.0
d3setlocal 0,0,0, cos( observer_t ),sin( observer_t ),0, -sin( observer_t ),cos( observer_t ),0, 0,0,1
// 奥行きを計算。遠くにあるものほどpanel_farは小さくなる
repeat PANEL_MAX
panel_far( cnt ) = cos( panel_t( cnt ) - observer_t ) * panel_r( cnt )
loop
// 小さい順(昇順)に並べ替え
sortval panel_far, 0
return
*draw
redraw 0
hsvcolor 0, 0, ( sin( observer_t ) + 1.0 ) * 128 : boxf
repeat PANEL_MAX
sortget i, cnt // 奥から数えてcnt番目のパネルのインデックス
x = cos( panel_t( i ) ) * panel_r( i ), cos( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), cos( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), cos( panel_t( i ) ) * panel_r( i )
y = sin( panel_t( i ) ) * panel_r( i ), sin( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), sin( panel_t( i ) ) * ( panel_r( i ) + PANEL_SIZE ), sin( panel_t( i ) ) * panel_r( i )
z = panel_z( i ) + PANEL_SIZE, panel_z( i ) + PANEL_SIZE, panel_z( i ), panel_z( i )
hsvcolor panel_h( i ), panel_s( i ), panel_v( i )
d3square x, y, z
loop
redraw 1
return
2007年7月16日月曜日
波紋のエフェクト(3次元ver.)
d3moduleを利用した波紋のエフェクトの3次元版。波の高さによって明るさが変わるようにもなっています。#include "d3m.hsp"
#define ctype round(%1) double(strf("%%0.0f", %1)) // 四捨五入(hspmathより抜粋)
#const CONST_A 0.1 // 定数その1。波長を決定付ける。
#const CONST_B 7 // 定数その2。屈折の程度を決定付ける。
buffer 1
onclick goto *start
*start
onclick 0
dialog "jpg;*.gif;*.bmp", 16
if stat == 0 : end
gsel 1 : picload refstr
sizeX = ginfo_winx
sizeY = ginfo_winy
centerX = ginfo_winx / 2
centerY = ginfo_winy / 2
screen 0, sizeX, sizeY, SCREEN_NORMAL
gmode GMODE_GDI, sizeX, sizeY
gcopy 1, 0, 0
d3setcam sizeX/2, -300, sizeY/4, sizeX/2, 0, sizeY/2
redraw 0
boxf
gmode GMODE_MEM, 1, 1
repeat sizeY : targetY = cnt
title "変換中…" + str(100 * cnt / sizeY) + "%"
repeat sizeX : targetX = cnt
// 中心から見た座標を算出。
d3getpos vx, vy, targetX, 0, targetY
dx = vx - centerX
dy = centerY -vy
// 中心から見た角度と距離を算出。
theta = atan(dy, dx)
dist = sqrt(dx * dx + dy * dy)
// ここがポイント。sinで屈折する距離を決めています。
// ラスタースクロールのスクリプトのほうが分かりやすいかもしれません。
copyX = centerX + round(cos(theta) * (dist + sin(dist * CONST_A) * CONST_B))
copyY = centerY + round(sin(theta) * (dist + sin(dist * CONST_A) * CONST_B))
pos targetX, targetY
gmode GMODE_ALPHA, 1, 1, absf(sin(dist * CONST_A)) * 64 + 192
gcopy 1, copyX, copyY
loop
await 10
loop
redraw 1
title "変換終了 - クリックで再開"
onclick 1
stop
2007年6月8日金曜日
ワープゾーン
d3moduleによるワープゾーンっぽい表現。
これは半年近く前に書いたスクリプトなのですが、今思うとlength()関数を使うべき箇所や悪い変数名が散見されます。#include "d3m.hsp"
randomize
repeat 50
t(cnt) = 0.02*rnd(314)
y(cnt) = rnd(500)
loop
screen 0, 480, 320
d3setcam 0, 0, 0, 0, 700, 0
*main
redraw 0
color : boxf
color 191,191
repeat 50
d3initlineto
d3ribbonto cos(t(cnt))*100, y(cnt), sin(t(cnt))*100, cos(t(cnt) + 0.05)*100, y(cnt), sin(t(cnt) + 0.05)*100
d3ribbonto cos(t(cnt))*100, y(cnt) + 200, sin(t(cnt))*100, cos(t(cnt) + 0.05)*100, y(cnt) + 200, sin(t(cnt) + 0.05)*100
y(cnt) -= 20
if y(cnt) < 0 {
t(cnt) = 0.02*rnd(314)
y(cnt) = rnd(700) + 200
}
loop
redraw
wait 2
goto *main
2007年5月22日火曜日
シェルピンスキーのギャスケット
シェルピンスキーのギャスケットを再帰を利用して描画。
そのままではつまらないので3D表示に。#include "d3m.hsp"
#module Gasket
#deffunc drawGasket double x1, double y1, double x2, double y2, double x3, double y3, int count
// X-Y平面上にシェルピンスキーのギャスケットを描く
if count {
drawGasket x1, y1, (x1 + x2)/2, (y1 + y2)/2, (x1 + x3)/2, (y1 + y3)/2, count - 1
drawGasket x2, y2, (x1 + x2)/2, (y1 + y2)/2, (x2 + x3)/2, (y2 + y3)/2, count - 1
drawGasket x3, y3, (x1 + x3)/2, (y1 + y3)/2, (x2 + x3)/2, (y2 + y3)/2, count - 1
} else {
d3initlineto
d3lineto x1, y1, 0
d3lineto x2, y2, 0
d3lineto x3, y3, 0
d3lineto x1, y1, 0
}
return
#global
redraw 0
d3setcam -30, -40, 90, 50, 43, 0
color : boxf
color 0, 128
drawGasket 0, 0, 100, 0, cos(3.14/3) * 100, sin(3.14/3) * 100, 4
redraw 1
stop
2007年5月4日金曜日
砲弾の射出(d3module)
目標地点を指定すると、そのために必要な射出方向を計算する。
射出速度は一定なので、遠方を狙うほど早く着弾する。// ang ... 角度, pos ... 位置(座標), velo... 速さ
// distance ... 距離, b ... 放物線の第2係数
#include "d3m.hsp"
#module powModule
#defcfunc pow double d1, int i2, local st
st = 1.0
repeat i2
st *= d1
loop
return st
#global
#const GRAVITY 1.0 // 重力加速度
#const VELOCITY 30.1 // 射出速度
#const DISTANCE_MAX VELOCITY * VELOCITY / GRAVITY // 最大飛距離
#const GRID_MAX 8 // グリッドの本数
#const GRID_DISTANCE 100 // グリッドの間隔
#const TARGET_RADIUS 10 // 照準の半径
#const BULLET_RADIUS 8 // 砲弾の半径
screen 0, 480, 480
// 射出点の座標
posCannonX = double(GRID_MAX) * GRID_DISTANCE / 2
posCannonY = 0.0
posCannonZ = 0.0
// 照準の座標
posTargetX = double(GRID_MAX) * GRID_DISTANCE / 2
posTargetY = double(GRID_MAX) * GRID_DISTANCE / 2
posTargetZ = 0.0
d3setcam GRID_MAX * GRID_DISTANCE / 2, -300, 200, GRID_MAX * GRID_DISTANCE / 2, GRID_MAX * GRID_DISTANCE / 2, 0
*main
gosub *move
gosub *draw
wait 4
goto *main
*move
stick key, 15
if key & 16 : gosub *shot
// 照準の移動
posTargetX += 10 * (((key >> 2) & 1) - (key & 1))
posTargetY += 10 * (((key >> 1) & 1) - ((key >> 3) & 1))
// 砲弾の移動
if posBulletZ >= 0 {
posBulletX += veloBulletX
posBulletY += veloBulletY
posBulletZ += veloBulletZ
veloBulletZ -= GRAVITY
}
return
*shot
// 射出 ここらへんのスクリプトの理解は力学と微分の知識が要ります
posBulletX = posCannonX
posBulletY = posCannonY
posBulletZ = posCannonZ
angBullet = atan(posTargetY - posCannonY, posTargetX - posCannonX)
distance = limitf(sqrt(pow(posTargetX - posCannonX, 2) + pow(posTargetY - posCannonY, 2)), 0.0, DISTANCE_MAX)
b = DISTANCE_MAX / distance + sqrt(pow(DISTANCE_MAX / distance, 2) - 1)
veloBulletR = sqrt(GRAVITY * distance / b / 2)
veloBulletZ = b * veloBulletR
veloBulletX = veloBulletR * cos(angBullet)
veloBulletY = veloBulletR * sin(angBullet)
return
*draw
redraw 0
color : boxf
color 0, 255 // グリッド
repeat GRID_MAX + 1
d3line cnt * GRID_DISTANCE, 0, 0, cnt * GRID_DISTANCE, GRID_MAX * GRID_DISTANCE, 0
d3line 0, cnt * GRID_DISTANCE, 0, GRID_MAX * GRID_DISTANCE, cnt * GRID_DISTANCE, 0
loop
color 255 // 照準
d3circle posTargetX, posTargetY, posTargetZ, TARGET_RADIUS, 0
if posBulletZ >= 0 {
color 0, 0, 255 // 砲弾
d3circle posBulletX, posBulletY, posBulletZ, BULLET_RADIUS
color 191, 191, 191 // 影
d3circle posBulletX, posBulletY, 0, BULLET_RADIUS
}
redraw 1
return
3次元空間を反射する光線
モジュール変数によるキャラクター管理法。
d3moduleを利用しています。
d3box命令を使って修正。(2007/10/02)#include "d3m.hsp"
#const global BOX_X 200
#const global BOX_Y 300
#const global BOX_Z 150
#const CAMERA_DISTANCE 500
#const BALL_MAX 30
#module physics3d x, y, z, vx, vy, vz
#modinit double d1, double d2, double d3, double d4, double d5, double d6
x = d1, d1, d1, d1
y = d2, d2, d2, d2
z = d3, d3, d3, d3
vx = d4 : vy = d5 : vz = d6
return
#modfunc moveBall
x(1) = x, x(1), x(2)
y(1) = y, y(1), y(2)
z(1) = z, z(1), z(2)
x += vx : y += vy : z += vz
if ( x < 0 ) | ( BOX_X < x ) : vx *= -1
if ( y < 0 ) | ( BOX_Y < y ) : vy *= -1
if ( z < 0 ) | ( BOX_Z < z ) : vz *= -1
return
#modfunc drawBall
d3initlineto
repeat 4
d3lineto x(cnt), y(cnt), z(cnt)
loop
return
#global
screen 0, 400, 370
title "3次元を反射する光線"
theta = 0.0 // カメラの角度 (極座標)
phi = 3.14 / 2 // カメラの角度2(極座標)
gosub *setcam
repeat BALL_MAX
newmod ball, physics3d, rnd(200), rnd(300), rnd(150), (rnd(9)-4)*3, (rnd(9)-4)*4, (rnd(9)-4)*3
loop
*main
gosub *moveCam
gosub *draw
wait 4
goto *main
*moveCam
stick key, 15
if key & 15 {
theta += 0.1*((key & 1) - (key >> 2 & 1))
phi = limitf(phi + 0.1*((key >> 1 & 1) - (key >> 3 & 1)), 0.1, 3.13)
// ↑ カメラのXY座標がターゲットと同じにならないための対策
gosub *setcam
}
return
*draw
redraw 0
color : boxf
hsvcolor 30, 255, 100
d3box 0, 0, 0, BOX_X, BOX_Y, BOX_Z
hsvcolor 30, 255, 255
foreach ball
moveBall ball(cnt)
drawBall ball(cnt)
loop
redraw
return
*setcam
d3setcam sin(phi)*cos(theta)*CAMERA_DISTANCE + 100, sin(phi)*sin(theta)*CAMERA_DISTANCE + 150, cos(phi)*CAMERA_DISTANCE + 75, 100, 150, 75
return



