takeyohのおぼえがき

気になったこと、試したことの記録です。

lua scriptでアプリを作り、ウィンカー音を出してみた

一つ前の覚書で書いた通り、現在のCSP(具体的には1.77以降)では、luaスクリプトを使って、wavやmp3などの音データを再生できることがわかりました。

同時に、今までpythonで書いていたアプリケーション類が、lua scriptでも書けるようになっています。ってことは、lua scriptでアプリを作れば、外部アプリを使わなくてもウィンカーの音が鳴らせるのでは?ということで覚書です。

 

最初はpythonを使って挑戦しました。音を出すのは簡単だったのですが、問題はウィンカーの点灯消灯のステータスが認識できないことでした。pythonのライブラリではCSPの拡張機能が認識できません。しかし、lua scriptバージョンであれば、CSPの拡張機能も認識できます。すばらしい~!

 

どういうアプリなのかの確認とアプリのダウンロードはこちらからできます。

youtu.be

 

インストールすると、assettocorsaのフォルダの下でapps/lua/blinkerというフォルダができます。

blinker.luaスクリプト本体、blinker.mp3がウィンカーの音、icon.pngはゲーム開始後の右メニューに表示されるときのアイコンの絵、manifest.iniは設定ファイル(みたいなもの)です。

まずmanifest.iniの一部WINDOWセクションです。

[WINDOW_...]
ID = main
NAME = Blinker Sound
ICON = icon.png
FUNCTION_MAIN = windowMain
SIZE = 400, 300

これは、このアプリの設定画面を表示するためのウィンドウ設定です。これが無いと、画面に文字や画像などの表示ができません。

 

続いて、blinker.luaの中身です。

local carSounds = ui.MediaPlayer()

local soundSetting = 0
-- soundSetting 0:road or street only  1:all cars
local soundVolume = 1
local value, changed

ここまでは各種変数の宣言パートです。

一番上のui.MediaPlayer()が使えるようになったのが一番大きなポイントですね。

soundSettingはroad,streetクラス車のみ音を出すか、全車音を出すかの判別フラグ。

soundVolumeはウィンカーの音量。(1は100%のことです。)

 

local mp3File = ac.getFolder(13) .. "\\" .. ac.getCarID(0) .. "\\extension\\blinker.mp3"
local wavFile = ac.getFolder(13) .. "\\" .. ac.getCarID(0) .. "\\extension\\blinker.wav"
local soundFile

if io.fileExists(mp3File) then
    soundFile = mp3File
elseif io.fileExists(wavFile) then
    soundFile = wavFile
else
    soundFile = './blinker.mp3'
end
carSounds:setSource(soundFile):setAutoPlay(false)

ここはウィンカーの音を選択しているパートです。

自車のcar modフォルダのextensionフォルダ内にblinker.mp3かblinker.wavのどちらかのファイルが存在すればそのファイルを、無い場合はアプリのフォルダ内にあるblinker.mp3を選択しています。(soundFile変数に使う音ファイルのパスを格納し、carSoundsにセット。)

setAutoPlayはtrueにするとこの処理時に即時音が再生されます。今回はウィンカーがついている時だけ音を出したいので、ここではfalseにしてます。

 

次は一つ飛んで、windowMainパート

function script.windowMain(dt)
  if ui.radioButton('road & street car only', soundSetting==0) then
    soundSetting = 0
  end
  if ui.radioButton('all cars', soundSetting==1) then
    soundSetting = 1
  end
  value, changed = ui.slider('volume', soundVolume, 0, 1, '%.2f')
  if changed then
    soundVolume = value
  end
  ui.text('sound file')
  ui.text(soundFile)
end

ここでは、manifestで設定したウィンドウの中身を設定しています。

具体的にはラジオボタン2つ(road, streetクラス車のみか、全車を選択)と、ボリュームを設定するスライダー(0%~100%)、それと、選択された音ファイルを表示しています。

radioButtonは横に表示する説明書きと、チェックがついた状態にするかどうかの判別文が引数にあり、radioButtonが押されたことをif文で判別してます。

一方、sliderはスライド後の値とスライドさせたことのフラグを変数に格納(この例ではvalueとchanged)し、フラグをチェックして値が変化したことをif文で判別しています。

ui.textは表示する文字列を引数に格納しています。

 

function update(dt)
  if ac.getCar().isCameraOnBoard and (ac.getCar().hazardLights or ac.getCar().turningLeftLights or ac.getCar().turningRightLights) then
    if soundSetting == 1 or (soundSetting == 0 and not ac.getCar().isRacingCar) then
    carSounds:setVolume(soundVolume)
        carSounds:play()
    end
  else
    carSounds:pause()
  end
end

最後はupdateパートです。これはゲーム中ずっとループしているパートになります。

windowMain部分で各種値を変数に格納すると、それがこのループ処理の中に反映される形ですね。

ac.getCar().isCameraOnBoardは視点がオンボード(車内)であるかどうか

ac.getCar().hazardLights or ac.getCar().turningLeftLights or ac.getCar().turningRightLightsはハザードか左ウィンカーか右ウィンカーのどれかが点いている状態であるかどうか

をチェックしていて、それをandでつないでいるので、両方の状態が満たされるときその中のルーチンが実行されます。それ以外の場合は、音を止めるcarSounds:pause()処理をします。

if文が入れ子になっていますが、中のif文はsoundSetting変数が1なら全車種なので無条件で音を鳴らし、sounrdSetting変数が0の場合は車がレーシングカーでは”ない”ことをチェックしています。

 

javascriptpython、coffeeなどスクリプト系言語に触れたことがある方ならすぐ理解できると思います。(もちろんプログラミング言語をご存じの方も)

超シンプルなスクリプト構成になっているので、lua scriptによるアプリ作成のベースにもなるかと思います。参考になれば幸いです。

 

 

 

/* -----codeの行番号----- */