AeroBeat

BMS (Be-Music Source file) プレイヤー。

独自の DSL (Domain-Specific Language) を用いたスキンシステムを搭載。従来の CSV (Comma-Separated Values) 形式のスキン定義と比べて記述量が少なく、テキストエディタで容易に編集できる。

スクリーンショットで使用しているスキンは LR2 用のスキン EndlessCirculation のパーツ画像を用いたものである。スキン画像の再配布となるため、このアプリケーション用のスキンは公開していない。

技術スタック

ゲーム本体

  • C++
  • DirectX (DX ライブラリ)
  • Boost.Spirit.Qi
  • PortAudio
  • SQLite

設定ツール

  • C#
  • XAML
  • .NET Framework
  • WPF (Windows Presentation Foundation)
  • MVVM (Model-View-ViewModel)

プリプロセッサを除いたスキンの構文 (BNF)

          <skin> ::= <element>*
       <element> ::= <image_ss> | <generic_def>
      <image_ss> ::= <source> "=" <string_literal>
   <generic_def> ::= <identifier> [<source>] [<src_params>] [<conditions>] [<dst_params>]
        <source> ::= "[" <identifier> "]"
    <src_params> ::= "(" <parameters> ")"
    <conditions> ::= "<" <condition_list> ">"
    <dst_params> ::= "{" <parameters> "}"
    <identifier> ::= (<alphabet> | "_") (<alphabet> | <number> | "_")*
   <identifiers> ::= <identifier> ("," <identifier>)*
<string_literal> ::= """ <any_character>+ """
     <parameter> ::= <identifier> ":" (<string_literal> | <identifier> | <timeline> | <double>)
    <parameters> ::= <parameter> ("," <parameter>)*
      <timeline> ::= "(" <identifier> ["," <double>] ")" "{" <keyframes> [","] "}"
      <keyframe> ::= <double> ":" <double> [<easing>]
        <easing> ::= "(" <identifier> ")"
     <keyframes> ::= <keyframe> ("," <keyframe>)*
     <condition> ::= ["!"] <identifier>
<condition_list> ::= <condition> ("," <condition>)*
      <alphabet> ::= "A" | ... | "Z" | "a" | ... | "z"
        <number> ::= "0" | ... | "9"
 <any_character> ::= any character
        <double> ::= double-precision floating-point number

スキン定義サンプル

#STARTINPUT "1"
#LOADEND "3"
#READY "1.5"
#FADEOUT "0.5"
#CLOSE "2.9"

// 画像定義
[object] = "ABFiles/Theme/EndlessCirculation/Play/common/object.png"
[graph] = "ABFiles/Theme/EndlessCirculation/Play/common/graph.png"
[note] = "ABFiles/Theme/EndlessCirculation/Play/note/DEFAULT.png"
[combo] = "ABFiles/Theme/EndlessCirculation/Play/combo/DEFAULT.png"
// ...

// グラフ
bargraph[graph](x: 0, y: 0, w: 1, h: 448, nx: 896, cycle: 10, id: score, direction: vertical) {
    x: 1044,
    y: 544,
    w: 75,
    h: (scene) {
        1.35: 0 (easeOutCubic),
        1.85: -444
    }
}

// ...

// 小節線
bar_line[object](x: 0, y: 390, w: 1, h: 1) {
    x: 50,
    y: 480,
    w: 288,
    h: 2
}

// ノーツ
note[note](type: note, index: 0, x: 0, y: 0, w: 60, h: 24)
note[note](type: note, index: 1, x: 61, y: 0, w: 34, h: 24)
note[note](type: note, index: 2, x: 96, y: 0, w: 26, h: 24)
note[note](type: note, index: 3, x: 61, y: 0, w: 34, h: 24)
note[note](type: note, index: 4, x: 96, y: 0, w: 26, h: 24)
note[note](type: note, index: 5, x: 61, y: 0, w: 34, h: 24)
note[note](type: note, index: 6, x: 96, y: 0, w: 26, h: 24)
note[note](type: note, index: 7, x: 61, y: 0, w: 34, h: 24)

// ...

// ジャッジ
image[combo](x: 0, y: 508, w: 124, h: 56, nx: 2, cycle: 0.08, timer: judge) <judge_poor_blank, judge> {
    x: 132,
    y: 351,
    a: (judge) {
        0: 255 (stop),
        0.5: 0
    }
}
image[combo](x: 0, y: 508, w: 124, h: 56, nx: 2, cycle: 0.08, timer: judge) <judge_poor, judge> {
    x: 132,
    y: 351,
    a: (judge) {
        0: 255 (stop),
        0.5: 0
    }
}

// ...
Screenshot
Screenshot
Screenshot
Screenshot