2023/09/10(日) [n年前の日記]
#1 [hsp] 疑似3D道路その7
_昨日
の続き。HSP 3.6 を使って、疑似3D道路が作れないか試しているところ。環境は Windows10 x64 22H2。
坂道は一応実装できた気がする。以下のような感じになった。
各セグメントの位置を縦方向にもずらしたら道路が隙間だらけになって、各セグメントに対して場当たり的に1ラスターだけ塗り潰す量を増やしたりもしたけれど…。テキトーに弄ってたらソレっぽくなってくれた。カーブが表現できたら、それを縦方向にも適用する、という感じでなんとかなる気がする。
坂道は一応実装できた気がする。以下のような感じになった。
各セグメントの位置を縦方向にもずらしたら道路が隙間だらけになって、各セグメントに対して場当たり的に1ラスターだけ塗り潰す量を増やしたりもしたけれど…。テキトーに弄ってたらソレっぽくなってくれた。カーブが表現できたら、それを縦方向にも適用する、という感じでなんとかなる気がする。
◎ ソース :
ソースは以下。
_road05.hsp
_road05_hsp (色分け表示)
使用画像は以下。.hsp と同じ場所に置く。
_bg_bg0.png
_bg_bg1.png
_trees.png
実行時、以下のキーを受け付ける。
_road05.hsp
_road05_hsp (色分け表示)
使用画像は以下。.hsp と同じ場所に置く。
_bg_bg0.png
_bg_bg1.png
_trees.png
実行時、以下のキーを受け付ける。
- Up : アクセル
- Down : ブレーキ
- Left, Right : 左右移動
- Z : 仮想画面の解像度変更
- X : フレームレート変更
◎ 動作させてみた状況 :
CPUで拡大縮小描画処理をしているせいか、それなりに処理が重いので、一旦、小さ目のサイズの仮想画面に描画してから、それを実ウインドウサイズに拡大描画している。
CPU : AMD Ryzen 5 5600X の環境で、実ウインドウサイズを 1600x900 にして動かしてみているけれど…。 *1
もしかして、元画像をあらかじめ拡大してイメージバッファに蓄えておいて、それをベタ転送したら多少は改善したり…。いや、それはメモリを滅茶苦茶食いそうか…。
CPU : AMD Ryzen 5 5600X の環境で、実ウインドウサイズを 1600x900 にして動かしてみているけれど…。 *1
- 仮想画面: 512x288 なら 60FPS も出せた。
- 仮想画面: 800x450 なら 30FPS が出せた。60FPS は処理落ちする。
- 仮想画面: 1280x720 なら 20FPS まで。30FPSは処理落ちする。
- 仮想画面: 320x180 なら 60FPS も余裕だったけど、画面はめっちゃ粗くなる。でも、昔のゲーム画面っぽい粗さではあるなと…。
もしかして、元画像をあらかじめ拡大してイメージバッファに蓄えておいて、それをベタ転送したら多少は改善したり…。いや、それはメモリを滅茶苦茶食いそうか…。
◎ gzoomを使った拡大縮小描画部分を手直し :
今回、HSP の gzoom を使ってビルボード(スプライト)の拡大縮小描画をしているけれど、画面外にはみ出しているはずの部分も一旦拡大描画してから仮想画面に転送していたので無駄な処理時間がかかっていた。そのあたりを改良して、画面内に収まっている部分だけを拡大描画するようにしてみた。
サンプルソースは以下。
_gzoom_03.hsp
使用画像は以下。
_trees.png
実行すると、カーソルキーでスプライトを上下左右に動かせる。スプライトが画面外に出始めると、画面上で表示している dest w,h の値が増減するので、適切な描画面積に変更してから描画してることが分かる。
サンプルソースは以下。
_gzoom_03.hsp
; 画面外にはみ出す分、幅や高さを減らして gzoom で拡大縮小描画
#define SCR_W 640
#define SCR_H 360
; #define SCR_W 1280
; #define SCR_H 720
#define FRAMERATE 60
; 同梱ファイル / bundled files
#define SPR_FILE "trees.png"
#pack SPR_FILE
#packopt name "gzoom_03" ; exe filename
#packopt type 0 ; generate ".exe"
#packopt xsize SCR_W
#packopt ysize SCR_H
; onkey goto *jobend
randomize 0
; get windows size
screen 0, SCR_W, SCR_H, 0
gsel 0
; width SCR_W, SCR_H
dispw = ginfo_winx
disph = ginfo_winy
cls 4
; load spite image
sprimgid0 = 6
buffer sprimgid0, 1024, 512
picload SPR_FILE
spr0w = ginfo_winx
spr0h = ginfo_winy
; init temporary image buffer
tmpid = 7
buffer tmpid, 4096, 4096
x = 16
y = 16
*mainloop
#define KEY_ESC 128
#define KEY_UP 2
#define KEY_DOWN 8
#define KEY_LEFT 1
#define KEY_RIGHT 4
#define KEY_CTRL 64
; ESC key to exit
stick k, 255
if k & KEY_ESC : goto *jobend
; check cursor key
spd = 8
if k & KEY_CTRL : spd = 1
if k & KEY_UP : y -= spd
if k & KEY_DOWN : y += spd
if k & KEY_LEFT : x -= spd
if k & KEY_RIGHT : x += spd
; 描画開始 / draw start
redraw 0
gsel 0
gmode gmode_gdi
; clear screen
color 32, 64, 128
boxf 0, 0, dispw, disph
; draw sprite
imgid = sprimgid0
imgw = spr0w
imgh = spr0h
dx = x
dy = y
scale = 1.5
dw = int(256.0 * scale)
dh = int(256.0 * scale)
n = 5 ; sprite No.
draw_sprite_gzoom dx, dy, dw, dh, imgid, imgw, imgh, n, tmpid, dispw, disph, 0
; draw text
font "Arial", 18, 1
color 255, 255, 255
pos 6, 6
mes "Push cursor key"
redraw 1 ; 描画終了 / draw end
await (1000 / FRAMERATE)
goto *mainloop
#module
#deffunc draw_sprite_gzoom int dst_x, int dst_y, int dst_w, int dst_h, int imgid, int imgw, int imgh, int n, int tmpid, int dispw, int disph, int dstid
; スプライト相当を拡大縮小して描画
;
; dst_x, dst_y : 描画先の左上座標
; dst_w, dst_h : 描画先のサイズ
; imgid : 元画像バッファID
; imgw, imgh : 元画像サイズ
; n : スプライトNo.
; tmpid : 作業用イメージバッファID
; dispw, disph : 画面サイズ
; dstid : 描画先イメージバッファID
; テクスチャのソース座標を算出
src_w = (imgw / 4)
src_h = (imgh / 2)
src_x = (n & 3) * src_w
src_y = ((n >> 2) & 1) * src_h
if dst_x >= dispw or (dst_x + dst_w) < 0 : return
if dst_y >= disph or (dst_y + dst_h) < 0 : return
dx = dst_x
dy = dst_y
dw = dst_w
dh = dst_h
sx = src_x
sy = src_y
sw = src_w
sh = src_h
; 画面外になっている分、幅や高さを減らす
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, imgid, 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
gmode gmode_gdi
if 1 {
; draw text
gmode gmode_gdi
font "Arial", 18, 1
color 255, 255, 255
pos 6, 28
mes "x, y = " + dst_x + ", " + dst_y + " dest w,h = " + dw + ", " + dh
}
return
#global
*jobend
end
使用画像は以下。
_trees.png
実行すると、カーソルキーでスプライトを上下左右に動かせる。スプライトが画面外に出始めると、画面上で表示している dest w,h の値が増減するので、適切な描画面積に変更してから描画してることが分かる。
◎ 課題 :
遠景の縦方向スクロールがどうもイマイチ。試しでテキトーに書いてみたけれど、仕組みについてもうちょっとしっかり考えないとダメだなと…。
また、遠景については、HSP の gcopy を使ってベタ転送・等倍で描画してるので、仮想画面サイズを変更すると見た目が変わってしまう。遠景も拡大縮小描画しないとダメかなと…。そもそも遠景の画像サイズが小さ過ぎる気もする。
各ビルボードの見た目が粗い気がする。1つにつき、テクスチャサイズを256x256で用意しているけれど、512x512ぐらいにしてみたほうがいいだろうか。遠景も画像サイズを変えたいし、画像関係は全部作り直ししたほうがいいかな…。
また、遠景については、HSP の gcopy を使ってベタ転送・等倍で描画してるので、仮想画面サイズを変更すると見た目が変わってしまう。遠景も拡大縮小描画しないとダメかなと…。そもそも遠景の画像サイズが小さ過ぎる気もする。
各ビルボードの見た目が粗い気がする。1つにつき、テクスチャサイズを256x256で用意しているけれど、512x512ぐらいにしてみたほうがいいだろうか。遠景も画像サイズを変えたいし、画像関係は全部作り直ししたほうがいいかな…。
*1: ソースの最初のあたりのコメントアウトを変更すればウインドウサイズを変更できる。
[ ツッコむ ]
以上、1 日分です。
