; 疑似3D道路を描画する / Drawing pseudo 3D roads ; 仮想画面解像度が変更されても遠景の見た目が同じになるようにした ; ; Up, Down key : アクセル,ブレーキ ; Left, Right key: 横移動 ; Z key : 仮想画面の解像度変更 ; X key : フレームレート変更 ; ; 2023/09/14 by mieki256 #include "hspmath.as" ; 実画面解像度 ; 16:9 ; #define SCR_W 640 ; #define SCR_H 360 #define SCR_W 1280 #define SCR_H 720 ; #define SCR_W 1600 ; #define SCR_H 900 ; #define SCR_W 1920 ; #define SCR_H 1080 ; 4:3 ; #define SCR_W 640 ; #define SCR_H 480 ; #define SCR_W 800 ; #define SCR_H 600 ; #define SCR_W 1024 ; #define SCR_H 768 ; #define SCR_W 1200 ; #define SCR_H 900 ; フレームレート dim framerate_list, 7 framerate_list(0) = 10 framerate_list(1) = 15 framerate_list(2) = 20 framerate_list(3) = 25 framerate_list(4) = 30 framerate_list(5) = 50 framerate_list(6) = 60 framerate_idx = 4 ; 配列初期化用マクロ #define set_array_n2(%1, %2, %3, %4) \ %1(%2, 0) = %3 :\ %1(%2, 1) = %4 : ; 仮想画面解像度 dim vscr_size, 6, 2 set_array_n2 vscr_size, 0, 320, 180 set_array_n2 vscr_size, 1, 480, 270 set_array_n2 vscr_size, 2, 512, 288 set_array_n2 vscr_size, 3, 640, 360 set_array_n2 vscr_size, 4, 800, 450 set_array_n2 vscr_size, 5, 1280, 720 ; set_array_n2 vscr_size, 6, 1920, 1080 vscr_size_idx = 3 VSCR_W_MAX = 1920 VSCR_H_MAX = 1080 ; セグメントの区切りを色分け. 0 or 1 or 2 #define SEG_DELIMITER 0 ; 同梱ファイル / bundled files #define SPR_FILE "trees.png" ; #define BG0_FILE "bg_2560x1440.png" #define BG0_FILE "bg_2560x1440.jpg" #pack SPR_FILE #pack BG0_FILE #packopt name "road07" ; exe filename #packopt type 0 ; generate ".exe" #packopt xsize SCR_W #packopt ysize SCR_H randomize 0 ; get windows size screen 0, SCR_W, SCR_H, 0 gsel 0 screen_w = ginfo_winx screen_h = ginfo_winy cls 4 ; init virtual screen buffer vscrbufid = 1 buffer vscrbufid, VSCR_W_MAX, VSCR_H_MAX dispw = vscr_size(vscr_size_idx, 0) disph = vscr_size(vscr_size_idx, 1) ; init temporary image buffer tmpid = 4 buffer tmpid, 4096, 4096 ; load spite image sprimgid0 = 5 buffer sprimgid0, 2048, 2048 picload SPR_FILE spr0w = ginfo_winx spr0h = ginfo_winy ; load bg image and scaling gosub *init_bg ; 2次元配列初期化用マクロ #define set_array_n4(%1, %2, %3, %4, %5, %6) \ %1(%2, 0) = %3 :\ %1(%2, 1) = %4 :\ %1(%2, 2) = %5 :\ %1(%2, 3) = %6 : ; texture table ; set_array_n4 配列変数名, index, x, y, w, h dim tex_pos, 8, 4 set_array_n4 tex_pos, 0, 0, 0, 512, 512 set_array_n4 tex_pos, 1, 512, 0, 512, 512 set_array_n4 tex_pos, 2, 1024, 0, 512, 512 set_array_n4 tex_pos, 3, 1536, 0, 512, 512 set_array_n4 tex_pos, 4, 0, 512, 512, 512 set_array_n4 tex_pos, 5, 512, 512, 512, 512 set_array_n4 tex_pos, 6, 0, 1024, 512, 128 set_array_n4 tex_pos, 7, 1024, 512, 1024, 512 ; init road y, width road_y = 100 ; 道路のy位置 road_x = 300 ; 道路の幅(片側の幅) ; ビルボード(billboard) 種類定義 #define BB_TREE 1 #define BB_ARROWR 2 #define BB_ARROWL 3 #define BB_GRASS 4 #define BB_BEAM 5 ; セグメント作成用データ ; set_array_n4 配列変数名, index, count, curve, pitch, billboard ; curve と pitch は100倍した値。 ; HSPは int と double を配列内で混在できないらしいので… dim segm, 25, 4 set_array_n4 segm, 0, 25, 0, 0, 0 set_array_n4 segm, 1, 28, 0, 0, BB_BEAM set_array_n4 segm, 2, 30, 0, 0, BB_GRASS set_array_n4 segm, 3, 20, 0, 0, BB_ARROWL set_array_n4 segm, 4, 80, 200, 0, BB_TREE set_array_n4 segm, 5, 10, 0, 0, BB_TREE set_array_n4 segm, 6, 80, 0, -50, BB_GRASS set_array_n4 segm, 7, 20, 0, 0, BB_ARROWR set_array_n4 segm, 8, 10, -100, 0, BB_GRASS set_array_n4 segm, 9, 50, -400, 0, BB_TREE set_array_n4 segm, 10, 20, 0, 0, 0 set_array_n4 segm, 11, 50, 0, 100, BB_GRASS set_array_n4 segm, 12, 40, 0, -100, BB_TREE set_array_n4 segm, 13, 60, -50, 0, BB_TREE set_array_n4 segm, 14, 50, 0, 0, BB_GRASS set_array_n4 segm, 15, 20, 0, 0, BB_ARROWL set_array_n4 segm, 16, 20, 200, 0, 0 set_array_n4 segm, 17, 30, 0, 0, BB_GRASS set_array_n4 segm, 18, 40, -80, -80, BB_TREE set_array_n4 segm, 19, 20, 0, 80, 0 set_array_n4 segm, 20, 20, 0, 0, BB_GRASS set_array_n4 segm, 21, 40, 20, -60, BB_TREE set_array_n4 segm, 22, 20, 0, 60, BB_GRASS set_array_n4 segm, 23, 50, 0, 0, BB_GRASS set_array_n4 segm, 24, 50, 0, 0, BB_TREE ; セグメント総数を取得 seg_max = 0 repeat length(segm) seg_max += segm(cnt, 0) loop ; セグメントのz幅を指定 seg_length = 20 seg_total_length = seg_length * seg_max ; 参照されるセグメントデータとして展開 dim seg, seg_max, 6 gosub *expand_segment ; 画面に描画するセグメントの個数 seg_distance = 160 ; セグメントの画面上の位置を記録するバッファ ddim seg_x0, seg_distance ddim seg_y0, seg_distance ddim seg_z0, seg_distance ddim seg_cx0, seg_distance ; セグメントに付随するビルボード情報を記録するバッファ dim seg_spr_kind, seg_distance ddim seg_spr_x, seg_distance ddim seg_spr_scale, seg_distance ; 画面までの距離 / distance to screen #define FOV 120.0 dist = double(dispw / 2) / tan(deg2rad(FOV / 2)) #define SPR_Z_LIMIT (184.0 / 2.0) camera_z = 0.0 spd = 0.0 xd = 0.0 yd = 0.0 zd = double(seg_length) bg_x = 0.0 bg_y = 0.0 px = 0.0 ppx = 0.0 angle = 0.0 fps_change = 0 vscr_change = 0 gosub *set_framerate *mainloop #define KEY_ESC 128 #define KEY_UP 2 #define KEY_DOWN 8 #define KEY_LEFT 1 #define KEY_RIGHT 4 #define KEY_Z 2048 #define KEY_X 4096 #define KEY_PRESS (KEY_ESC+KEY_UP+KEY_DOWN+KEY_LEFT+KEY_RIGHT) stick k, KEY_PRESS ; ESC key to exit if k & KEY_ESC : goto *jobend ; 仮想画面サイズを変更 if k & KEY_Z { if vscr_change == 0 { vscr_change = 1 vscr_size_idx = (vscr_size_idx + 1) \ length(vscr_size) dispw = vscr_size(vscr_size_idx, 0) disph = vscr_size(vscr_size_idx, 1) dist = double(dispw / 2) / tan(deg2rad(FOV / 2)) } } else { vscr_change = 0 } ; フレームレート変更 if k & KEY_X { if fps_change == 0 { fps_change = 1 oldspdper = spd / spd_max framerate_idx = (framerate_idx + 1) \ length(framerate_list) gosub *set_framerate spd = spd_max * oldspdper } } else { fps_change = 0 } gosub *set_framerate ; check cursor key if k & KEY_UP { spd += spda if spd >= spd_max : spd = spd_max } if k & KEY_DOWN { spd -= (spda * 3) if spd < 0.0 : spd = 0.0 } x_spd = (spd * 0.3) if k & KEY_LEFT : ppx += x_spd if k & KEY_RIGHT : ppx -= x_spd px = ppx angle += (spd * 0.05) base_y = int(double(disph) * 0.5) h = disph - base_y ; 最初のセグメント番号を取得 if camera_z = 0 { seg_index = 0 } else { ; "\"はHSPの剰余記号。一般的なプログラミング言語なら "%" に相当 seg_index = (int(camera_z) / seg_length) \ seg_max } ; カメラが居るセグメントのカーブ量とピッチ量を求める curve = double(seg(seg_index, 1)) * 0.01 pitch = double(seg(seg_index, 2)) * 0.01 ; カメラがセグメント内のどの位置に居るか割合を求める z0 = seg(seg_index, 0) z1 = z0 + seg_length ccz = camera_z \ seg_total_length camz = double(ccz - z0) / double(z1 - z0) ; セグメント内のカメラ位置に応じて事前に横方向にある程度ずらしておく camang = camz * curve xd = -camang yd = -camz * pitch zd = double(seg_length) cx = -(xd * camz) cy = -(yd * camz) cz = 0.0 ; BGのスクロール量を変更 gosub *calc_bg_pos ; 道路を描画するためのデータを計算 gosub *calc_road ; 描画開始 / draw start redraw 0 gsel vscrbufid ; 背景(遠景)を描画 / draw BG if SEG_DELIMITER <= 1 { bgid = bgimgid(vscr_size_idx) bw = bgw(vscr_size_idx) bh = bgh(vscr_size_idx) draw_bg vscrbufid, bg_x, bg_y, bgid, bw, bh, dispw, disph } else { gmode gmode_gdi color 0, 0, 0 boxf 0, 0, dispw, disph } ; 道路を描画 / draw road gosub *draw_road ; 仮想画面を実画面に転送 gsel 0 gmode gmode_gdi if screen_w == dispw and screen_h == disph { ; 等倍で転送 pos 0, 0 gcopy vscrbufid, 0, 0, dispw, disph } else { ; 拡大縮小して転送 xscale = double(screen_w) / double(dispw) yscale = double(screen_h) / double(disph) ; if xscale < yscale : scale = xscale : else : scale = yscale if xscale < yscale : scale = yscale : else : scale = xscale dstw = int(double(dispw) * scale) dsth = int(double(disph) * scale) dstx = (SCR_W - dstw) / 2 dsty = (SCR_H - dsth) / 2 pos dstx, dsty gzoom dstw, dsth, vscrbufid, 0, 0, dispw, disph, 0 } *draw_text if 1 { gsel 0 font "Arial", 16, 1, 2 color 1, 1, 1 objcolor 255, 255, 255 ; pos 8, 4 ; mes "Press cursor key" pos (SCR_W / 2) - 80, 2 mes "Res:" + dispw + "x" + disph + " " + int(nowframerate) + "fps", 4 pos (SCR_W / 2) - 120, 22 mes "bg_x, bg_y = " + bg_x + ", " + bg_y, 4 } redraw 1 ; 描画終了 / draw end camera_z += spd await (1000 / framerate_list(framerate_idx)) goto *mainloop *set_framerate nowframerate = double(framerate_list(framerate_idx)) spd_max = 960.0 / nowframerate spda = spd_max / (nowframerate * 3.0) if spd > spd_max : spd = spd_max if spd < 0.0 : spd = 0.0 return *draw_raster_road ; 道路を1ラスター分描画 / draw road 1 raster ; draw_x, draw_y : draw x, y ; road_w : road width ; kind : 0 or 1 or 2 ; dispw : screen width ; draw ground if kind = 0 { ; color R, G, B color 114, 185, 66 } else { color 22, 174, 63 } ; boxf x0, y0, x1, y1 boxf 0, draw_y, dispw, draw_y ; draw road base switch kind case 0 color 133, 149, 158 swbreak case 1 color 149, 168, 179 swbreak case 2 color 255, 0, 0 swbreak swend boxf draw_x, draw_y, draw_x + road_w, draw_y ; draw white line lw = double(road_w) * 48.0 / 2048.0 ; white line width switch kind case 0 color 255, 255, 255 lx = double(draw_x) boxf lx, draw_y, lx + lw, draw_y lx = lx + road_w - lw boxf lx, draw_y, lx + lw, draw_y lx = double(draw_x) + (double(road_w) * 0.5) - (lw * 0.5) boxf lx, draw_y, lx + lw, draw_y lx = double(draw_x) + double(road_w) * 0.25 - (lw * 0.5) boxf lx, draw_y, lx + lw, draw_y lx = double(draw_x) + double(road_w) * 0.75 - (lw * 0.5) boxf lx, draw_y, lx + lw, draw_y swbreak case 1 color 228, 236, 252 lx = double(draw_x) + lw boxf lx, draw_y, lx + lw, draw_y lx = double(draw_x) + road_w - (lw * 2) boxf lx, draw_y, lx + lw, draw_y swbreak swend return *get_easing_value ; イージングを考慮した値を返す ; ; easing : easing kind. 0 - 3 ; v0 : value 0 ; v1 : value 1 ; per : percent. 0.0 - 1.0 ; return ret_value if 1 { ; HSP のイージング関数を使って処理 switch easing case 0: ; not easing ret_value = v0 swbreak case 1: ; ease In setease v0, v1, ease_quad_in ret_value = int(geteasef(int(per * 4096), 4096)) swbreak case 2: ; ease Out setease v0, v1, ease_quad_out ret_value = int(geteasef(int(per * 4096), 4096)) swbreak case 3: setease v0, v1, ease_quad_inout ret_value = int(geteasef(int(per * 4096), 4096)) swbreak swend } else { ; 自前でイージング計算 v_diff = double(v1 - v0) switch easing case 0: ; not easing ret_value = v0 swbreak case 1: ; ease In ret_value = v0 + int(v_diff * (per * per)) swbreak case 2: ; ease Out ret_value = v0 + int(v_diff * (1.0 - ((1.0 - per) * (1.0 - per)))) swbreak case 3: if per < 0.5 { ret_value = v0 + int(v_diff * (2.0 * per * per)) } else { vv = -2.0 * per + 2.0 ret_value = v0 + int(v_diff * (1.0 - ((vv * vv) / 2.0))) } swbreak swend } return *set_billboard ; 各セグメントに記録するビルボード情報を決める ; ; billboard : ビルボード種類 ; road_x : 道路の幅(片側の幅) ; return spr_kind, spr_x, spr_scale switch billboard case 0 ; none spr_kind = 0 spr_x = 0 spr_scale = 0 swbreak case BB_TREE ; tree spr_kind = rnd(4) + 1 spr_x = rnd(400) + road_x + 100 if (rnd(2) & 1) == 0 : spr_x *= -1 spr_scale = 100 + rnd(100) swbreak case BB_ARROWR case BB_ARROWL ; arrow sign right to left, left to right if cnt \ 4 == 0 { ; arrow sign spr_kind = 5 + (billboard - BB_ARROWR) spr_x = road_x + 120 if billboard == 3 : spr_x *= -1 spr_scale = 100 } else { ; grass spr_kind = 7 spr_x = rnd(50) + road_x + 120 if billboard == 3 : spr_x *= -1 spr_scale = 100 } swbreak case BB_GRASS ; grass spr_kind = 7 spr_x = road_x + 200 + rnd(150) if (rnd(2) & 1) == 0 : spr_x *= -1 spr_scale = 150 + rnd(50) swbreak case BB_BEAM ; beam if cnt \ 7 = 0 { ; beam spr_kind = 8 spr_x = 0 spr_scale = 100 } else { ; none spr_kind = 0 spr_x = 0 spr_scale = 100 } swbreak swend return *draw_billboard ; draw billboard sprite ; ; spr_kind : kind. 0 = None, 1-4 = tree, 5-6 = sign ; spr_x : x position ; spr_scale : scale (double) ; z0, z1 : segment z value. segmnet[n] and segment[n+1] ; y0, y1 : segment y value. segmnet[n] and segment[n+1] ; cx0, cx1 : segment center x value. segmnet[n] and segment[n+1] ; dispw, disph : screen size ; dist : screen distance if spr_kind <= 0 : return switch spr_kind case 1 case 2 case 3 case 4 ; tree n = spr_kind - 1 spr_w = 450.0 spr_h = 450.0 swbreak case 5 case 6 ; arrow sign n = spr_kind - 1 spr_w = 200.0 spr_h = 200.0 swbreak case 7 ; grass n = 6 spr_w = 200.0 spr_h = 50.0 swbreak case 8 ; beam n = 7 spr_w = 1000.0 spr_h = 500.0 swbreak swend imgid = sprimgid0 imgw = spr0w imgh = spr0h z = double(z0) y = y0 cx = cx0 scale = spr_scale * double(dist) / z dst_w = int(spr_w * scale) dst_h = int(spr_h * scale) spr_xpos = (double(spr_x) * double(dist) / z) + cx dst_x = int(spr_xpos - (dst_w / 2) + (dispw / 2)) dst_y = int(y - dst_h + base_y) if SEG_DELIMITER == 0 { if z < SPR_Z_LIMIT : return ; gosub *draw_sprite_gzoom draw_sprite_gzoom vscrbufid, dst_x, dst_y, dst_w, dst_h, imgid, n, tmpid, dispw, disph, tex_pos } return #module #deffunc draw_sprite_gzoom int dstid, int dx, int dy, int dw, int dh, int srcid, int n, int tmpid, int dispw, int disph, array tex_pos ; スプライト相当を拡大縮小して描画 ; ; dstid : 描画先バッファID ; dx, dy, dw, dh : 描画先左上座標、サイズ ; srcid : 元画像バッファID ; n : スプライトNo. ; tmpid : 作業用イメージバッファID ; dispw, disph : 画面サイズ ; tex_pos : テクスチャ座標テーブル ; テクスチャの x, y, w, h を取得 sx = tex_pos(n, 0) sy = tex_pos(n, 1) sw = tex_pos(n, 2) sh = tex_pos(n, 3) draw_by_gzoom dstid, dx, dy, dw, dh, srcid, sx, sy, sw, sh, tmpid, dispw, disph return #global #module #deffunc draw_by_gzoom int dstid, int dstx, int dsty, int dstw, int dsth, int srcid, int srcx, int srcy, int srcw, int srch, int tmpid, int dispw, int disph ; 画面外にはみ出る分を考量して最小面積で画像を拡大縮小描画 ; ; dstid : 描画先バッファID ; dstx, dsty, dstw, dsth : 描画先左上座標, 描画先サイズ ; srcid : 元画像バッファID ; srcx, srcy, srcw, scrh : 元画像左上座標, 元画像サイズ ; tmpid : 作業用イメージバッファID ; dispw, disph : 画面サイズ dx = dstx dy = dsty dw = dstw dh = dsth sx = srcx sy = srcy sw = srcw sh = srch if dx >= dispw or (dx + dw) < 0 : return if dy >= disph or (dy + dh) < 0 : return if dx < 0 { w = (-dx) * sw / dw sx += w sw -= w dw += dx dx = 0 } if dy < 0 { h = (-dy) * sh / dh sy += h sh -= h dh += dy dy = 0 } if (dx + dw) > dispw { dwd = (dx + dw) - dispw swd = dwd * sw / dw sw -= swd dw -= dwd } if (dy + dh) > disph { dhd = (dy + dh) - disph shd = dhd * sh / dh sh -= shd dh -= dhd } ; gzoom は透明色を扱えないので小技が必要 ; 一旦、仮バッファに拡大縮小描画 gsel tmpid pos 0, 0 gzoom dw, dh, srcid, sx, sy, sw, sh, 0 ; 仮バッファから実スクリーンに gcopy でコピー ; gcopy なら RGB=(0,0,0) を透明色として扱える gsel dstid gmode gmode_rgb0 ; RGB=(0,0,0)を透明色として扱う pos dx, dy gcopy tmpid, 0, 0, dw, dh ; draw text if 0 { gmode gmode_gdi font "Arial", 18, 1 color 255, 255, 255 pos 4, 80 mes "x, y = " + dstx + ", " + dsty pos 4, 100 mes "dst x, y, w, h = " + dx + ", " + dy + " ," + dw + " ," + dh pos 4, 120 mes "src x, y, w, h = " + sx + ", " + sy + " ," + sw + " ," + sh } return #global *expand_segment ; 元になるセグメントデータから参照されるセグメントデータに展開 ; dim seg, seg_max, 6 z = 0 i = 0 repeat length(segm) n0 = cnt n1 = (cnt + 1) \ length(segm) lp = segm(n0, 0) curve = segm(n0, 1) pitch = segm(n0, 2) billboard = segm(n0, 3) next_curve = segm(n1, 1) next_pitch = segm(n1, 2) ; イージング有効無効 #define EASING_ENABLE 0 if EASING_ENABLE { ; カーブ量やピッチ量をイージングで求める場合 if curve == next_curve { curve_easing = 0 } else { if curve == 0 { curve_easing = 1 ; ease In } else { if next_curve == 0 { curve_easing = 2 ; ease Out } else { curve_easing = 3 ; ease In Out } } } if pitch == next_pitch { pitch_easing = 0 } else { if pitch == 0 { pitch_easing = 1 ; ease In } else { if next_pitch == 0 { pitch_easing = 2 ; ease Out } else { pitch_easing = 3 ; ease In Out } } } } repeat lp seg(i, 0) = z per = double(cnt) / double(lp) if EASING_ENABLE { ; カーブ量やピッチ量をイージングで求める v0 = curve v1 = next_curve easing = curve_easing gosub *get_easing_value seg(i, 1) = ret_value v0 = pitch v1 = next_pitch easing = pitch_easing gosub *get_easing_value seg(i, 2) = ret_value } else { ; カーブ量やピッチ量を線形補完で求める seg(i, 1) = curve + int(double(next_curve - curve) * per) seg(i, 2) = pitch + int(double(next_pitch - pitch) * per) } ; set billboard sprite gosub *set_billboard seg(i, 3) = spr_kind seg(i, 4) = spr_x seg(i, 5) = spr_scale z += seg_length i++ loop loop return *calc_road ; 道路を描画するための座標値を計算して記録 i = 0 seg_z_max = 0 repeat (seg_distance + 1) ; セグメントのz値、カーブ量、ピッチ量を取得 idx = (seg_index + cnt) \ seg_max z0 = seg(idx, 0) curve = double(seg(idx, 1)) * 0.01 pitch = double(seg(idx, 2)) * 0.01 ; 最後のセグメントを超えて最初にループする場合、z値を調整する if z0 > seg_z_max : seg_z_max = z0 if z0 < seg_z_max : z0 += seg_total_length cam_z = int(camera_z) \ seg_total_length z0 -= cam_z if z0 = 0 : z0 = 1 ; 0で除算しないように微調整 ; 画面上で描画すべきy座標位置を取得 y0 = (double(road_y) + cy) * dist / double(z0) ; 画面上で描画すべき道路の幅(片側の幅)を取得 x0 = double(road_x) * double(dist) / double(z0) ; 画面上でずらすべき中心線の位置を取得 cx0 = (double(cx) + px) * double(dist) / double(z0) ; 描画用に記録 seg_z0(i) = double(z0) seg_y0(i) = double(y0) seg_x0(i) = double(x0) seg_cx0(i) = double(cx0) ; スプライト相当の情報も記録 seg_spr_kind(i) = seg(idx, 3) seg_spr_x(i) = double(seg(idx, 4)) seg_spr_scale(i) = double(seg(idx, 5)) * 0.01 cx += xd cy += yd cz += zd xd += curve yd += pitch i++ loop return *draw_road ; 道路を描画 gmode gmode_gdi repeat seg_distance i = seg_distance - cnt - 1 i1 = seg_distance - cnt x0 = seg_x0(i) y0 = seg_y0(i) z0 = seg_z0(i) cx0 = seg_cx0(i) x1 = seg_x0(i1) y1 = seg_y0(i1) z1 = seg_z0(i1) cx1 = seg_cx0(i1) spr_kind = seg_spr_kind(i) spr_x = seg_spr_x(i) spr_scale = seg_spr_scale(i) if z1 < (SPR_Z_LIMIT / 2) : goto *seg_draw_cancel ; 各セグメントが作る台形を塗り潰す if SEG_DELIMITER <= 1 { ; y0 < y1 なら道路の裏面を見てる。描画をスキップ if y0 < y1 : goto *seg_draw_cancel h = abs(y1 - y0) + 1 dsy = sgn(y1 - y0) if dsy = 0 : dsy = 1 repeat h sy = y0 + (dsy * cnt) draw_y = sy + base_y ; 画面縦幅を超えたy座標なら描画しない if draw_y < 0 | draw_y > disph : continue ; 2次元的な計算で割合を求める if y0 == y1 { p = 0.0 } else { p = double(sy - y0) / double(y1 - y0) } z = (double(z1) - double(z0)) * p + double(z0) x = (double(x1) - double(x0)) * p + double(x0) center_x = (cx1 - cx0) * p + cx0 addv = ((int(z) + int(camera_z)) / 40) & $1 ; 1ラスター分を描画 / draw 1 raster road_w = x * 2 draw_x = -x + center_x + (dispw / 2) kind = addv if SEG_DELIMITER = 1 { ; セグメントの区切りを色分けしたい場合 if sy = y0 : kind = 2 } gmode gmode_gdi gosub *draw_raster_road loop } else { ; デバッグ用。セグメントの区切り線だけを描画 d = (dispw / 2) color 255, 0, 0 line cx0 + x0 + d, y0 + base_y, cx0 - x0 + d, y0 + base_y if 0 { line cx1 - x1 + d, y1 + base_y, cx0 - x0 + d, y0 + base_y line cx1 + x1 + d, y1 + base_y, cx0 + x0 + d, y0 + base_y } color 255, 255, 0 line cx1 + d, y1 + base_y, cx0 + d, y0 + base_y } *seg_draw_cancel ; draw billboard sprite if spr_kind <= 0 : continue gosub *draw_billboard loop return *init_bg ; load bg k = length(vscr_size) dim bgimgid, k dim bgw, k dim bgh, k i = k - 1 bgimgid(i) = 6 + i buffer bgimgid(i), 2560, 1440 picload BG0_FILE bgw(i) = ginfo_winx bgh(i) = ginfo_winy ; scaling repeat k - 1 bgw(cnt) = vscr_size(cnt, 0) * 2 bgh(cnt) = vscr_size(cnt, 1) * 2 bgimgid(cnt) = 6 + cnt buffer bgimgid(cnt), bgw(cnt), bgh(cnt) gsel bgimgid(cnt) gzoom bgw(cnt), bgh(cnt), bgimgid(i), 0, 0, bgw(i), bgh(i), 1 loop return *calc_bg_pos ; BGスクロール位置を計算 ; curve, pitch ; spd, spd_max ; bg_x, bg_y fper = 30.0 / nowframerate bg_x += curve * (spd / spd_max) * 0.1 * fper if spd > 0.0 { if pitch != 0.0 { bg_y += pitch * (spd / spd_max) * 0.1 * fper } else { d = (spd / spd_max) * 0.2 * fper if bg_y < 0.0 { bg_y += (d * 0.1) if bg_y >= 0.0 : bg_y = 0.0 } if bg_y > 0.0 { bg_y -= (d * 0.1) if bg_y <= 0.0 : bg_y = 0.0 } } ; bg_y += ((pitch * 2.0) - bg_y) * 0.15 if bg_y < -1.0 : bg_y = -1.0 if bg_y > 1.0 : bg_y = 1.0 } return #module #deffunc draw_bg int dstid, double bg_x, double bg_y, int bgimgid, int bgw, int bgh, int dispw, int disph ; BGを描画 / draw BG ; ; dstid : 描画先バッファID ; bg_x, bg_y : bg position. 0.0 - 1.0 ; bgimgid : bg images buffer ID. array. ; bgw, bgh : bg width, height. array. ; dispw, disph : screen width, height bx = bg_x by = bg_y if by < -1.0 : by = -1.0 if by > 1.0 : by = 1.0 bgid = bgimgid bw = bgw bh = bgh shiftx = bx sx = int(double(bh / 4) * bx) \ bw sy = int(double(bh / 4) * by) + (bh / 2) - (bh / 4) sw = dispw sh = disph gsel dstid gmode gmode_gdi if sx >= 0 and (sx + dispw) < bw { pos 0, 0 gcopy bgid, sx, sy, dispw, disph } else { if (sx + dispw) > bw : sx = (sx - bw) \ bw w = -sx sw0 = w sx0 = bw - w pos 0, 0 gcopy bgid, sx0, sy, sw0, sh sw1 = sw - w sx1 = 0 pos sw0, 0 gcopy bgid, sx1, sy, sw1, sh } return #global *jobend end