SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|

2024-06-11(Tue) 太郎くんはサーキットを時速100kmで走ることにしました

  一段落してしまった気分でしばらく放置してあった自作のレースゲームだが、近所のサーキットを走ってみたくなったので開発を再開することにした。

  まずは画面切り替えを故意に遅延していたのを是正する。厄介なのは地図タイルをネットワーク越しに得る都合上、故意でなくても少なくない遅延があることだ。処理を集中することなく、段階的に処理が進むよう、こんなコードを書いてみた。

draw: ->
    n = 0; while(n < @tile_reqs.length)
        tile_req = @tile_reqs[n]
        unless(tile_req[3])
            tile_req[3] = new Image                     # Image インスタンスを生成
        else unless(tile_req[4])
            tile_req[3].src = tile_req[2]               # Image.src を設定
            tile_req[4] = true
        else if(tile_req[3].complete)                   # 読み込み完了?
            @constructor.pats[0] = tile_req[3]
            @put_source_plane(@constructor.pats, 0, tile_req[0] << 8, tile_req[1] << 8) # ソースプレーン(回転前)に転送
            tile_req[5] = true                          # キューから削除せよ
        if(tile_req[5]) then @tile_reqs.splice(n, 1) else ++n

  要するに1フレームで複数の処理をすることを避け、分散させるわけだ。まだ試作段階なので、分散のアルゴリズムにはチューニングの余地があるが、とりあえずそれほど大きくはツッカカることなく走り続けられるようになった。

 

  例によって、録画の都合で15FPSになっているが、実際は60FPSで動いている。マップの更新遅延と多少のガクつきは実際にあるが。

  そこで改めて表題の問題だ。現状スペースキーを押すと固定速度で前進走行するようになっていて、それは0.3という適当な値を与えている結果なのだが、いったい時速何kmで走っているのだろう。別に「ゲームなんだから考えません」という方向性もあろうが、以前に書いたように「実際に遊んだときに実際のF1のラップに近いタイムが出るようにしたいと思っている」のであれば、その辺をキッチリさせる必要があるのだ。

  まずは、0.3で走っている現状の速度を求めてみよう。どうやるか。実際にコースを一定距離走らせ、経過時間を求めて算出すればいい。そうなると長い直線を持つコースが望ましいが……そうだ、昔、自分が働いていたつくばの土木研究所の試験走路を走らせてみよう。

  それより、ぼちぼちコースを選択するインタフェイスも欲しくなってきたな。URIにクエリで与えられると実用的だが、CoffeeScriptの場合どう受け取るんだろう。こうやんのか。

query = new URLSearchParams(window.location.search)
switch query.get('course')
    when 'silverstone'
        lng_d1 =   -1.022485; lat_d1 =   52.069097; v =  91 # シルバーストン
    when 'marinabay'
        lng_d1 =  103.864217; lat_d1 =    1.291532; v =  58 # マリーナベイ
    when 'doken'
        lng_d1 =  140.072549; lat_d1 =   36.115692; v = 184 # 土木研究所
    else
        lng_d1 =  136.540617; lat_d1 =   34.843099; v = 164 # 鈴鹿

  なんか懐かしいなぁ、って思いながら車を走らせていると、視界が恐ろしく狭いことに気づいた。試験走路から一般道に出て、当時の寮に帰ってみようと思ったのだが、どこを走っているのかわからず、帰れない。仕方ないので、より小縮尺のグーグルマップをすぐ右に別に開いて、それを参照しながらドライブしてみた。つうか、これは「ラリーX」じゃないのかw? それにしても、これだけでもだいぶ楽しいな。気づくと土浦学園線、土浦ニューウェイを通って土浦駅まで走っていってしまっていた。何をやってんだオレわw。

  画像の説明

  試験走路に戻ろう。とりあえず、わかりやすい目印を決めてそこまで走ろう。スタート地点からそこまでの距離を、グーグルマップの「距離を測定」機能で求める。1.03km。で、ストップウォッチを片手に、車を走らせる。29秒。「1.03km / 29s x 3600s = 127.9km/h」。おぉ、おおよそ時速100kmだったんだな。

  んが、ここからが問題。時速100kmになる「値」はいくつなのか。0.3より少し小さいはずだが、ここは安直に比率で求めるのではなく、理詰めで求めたい。

  まずは0.3が127.9km/hになった理由を求める。0.3は256分率表現で76.8。60FPSなので4608/s。ズームレベル20なので4ビット右シフトして288ピクセル/s。24ピクセルが2mなので24m/s。時速にすると86.4km/h……あれ? いや、地図の側を緯度補正して24ピクセルを2mにしてるんだから、速度の方も補正しなければならないのか。「86.4km/h x 256 / 178 = 124.26km/h」。おぉ、だいたい同じになった。計算は合っていそうだ。

  これを逆にして100km/hから求めればいい。「100km/h * 178 / 256 =69.53km/h」。秒速にすると19.31m/s。24ピクセルが2mなので232ピクセル/s。ズームレベル20なので4ビット左シフトして3708/s。60FPSなので61.8。256分率表現なので0.241。ということになる。んが、毎回こんな計算をするのは無駄なので、計算順序を入れ替えて定数にまとめてしまう。「0.3472 * 178 *1.0 / 256 = 0.241」緯度が変わったら178を変更し、200km/hにしたければ1.0を2.0に変更すればいいわけだ。

  念のため、土木研究所の試験走路でやった速度の算出を、シルバーストン、鈴鹿、マリーナベイでやってみたが、ちゃんと100km/hで走っているという結果が出た。よっしゃよっしゃ。

  これができたら、あとは鈴鹿のF1の走行映像からコーナリング速度を読み取り、ハンドルの効きを調整。それができたら、予選のラップタイムに近くなるように加減速の性能を調整。という段階を踏むことになるだろう。

  んが、その前にCourseクラスとMyCarクラスで個々に計算している緯度補正値をWposクラスに持っていくリファクタリングが先だな。まだまだ先は長そうだ。