diff options
author | Orangerot <purple@orangerot.dev> | 2024-12-28 23:41:36 +0100 |
---|---|---|
committer | Orangerot <purple@orangerot.dev> | 2024-12-28 23:41:36 +0100 |
commit | e9ba842e21503c00686e468729ad1f57ae96241b (patch) | |
tree | bf61626ba13f3ae0950daf018d443a264abc3e0c /lib/level.dart | |
parent | 9eb8a2938271ad9855f3d72cbbf10eb9ba607cf1 (diff) |
feat: display beats as arrows with correct time offset
Diffstat (limited to 'lib/level.dart')
-rw-r--r-- | lib/level.dart | 71 |
1 files changed, 54 insertions, 17 deletions
diff --git a/lib/level.dart b/lib/level.dart index 369a162..01083e2 100644 --- a/lib/level.dart +++ b/lib/level.dart @@ -13,6 +13,24 @@ class Level extends StatefulWidget { State<Level> createState() => _LevelState(); } +enum ArrowDirection { + left(Icons.arrow_back), + down(Icons.arrow_downward), + up(Icons.arrow_upward), + right(Icons.arrow_forward); + + const ArrowDirection(this.icon); + + final IconData icon; +} + +class Note { + final double time; + final ArrowDirection direction; + + const Note({required this.time, required this.direction}); +} + class _LevelState extends State<Level> { final player = AudioPlayer(); Simfile? simfile; @@ -23,6 +41,8 @@ class _LevelState extends State<Level> { StreamSubscription? _durationSubscription; StreamSubscription? _positionSubscription; + List<Note> notes = []; + @override void setState(VoidCallback fn) { // Subscriptions only can be closed asynchronously, @@ -79,6 +99,25 @@ class _LevelState extends State<Level> { simfile = Simfile(simfilePath); simfile!.load(); + double bpm = simfile!.bpms.entries.first.value; + + for (final (measureIndex, measure) + in simfile!.chartSimplest!.measures!.indexed) { + for (final (noteIndex, noteData) in measure.indexed) { + int arrowIndex = noteData.indexOf('1'); + if (arrowIndex < 0 || arrowIndex > 3) { + continue; + } + notes.add(Note( + time: (measureIndex * 4.0 + + (noteIndex.toDouble() / measure.length) * 4.0) * + 1.0 / + bpm + + simfile!.offset / 60.0, + direction: ArrowDirection.values[arrowIndex])); + } + } + print(audioPath); player.play(DeviceFileSource(audioPath)); @@ -86,7 +125,6 @@ class _LevelState extends State<Level> { @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( leading: IconButton( @@ -123,18 +161,16 @@ class _LevelState extends State<Level> { )), ), body: Stack(children: [ - Arrow( - position: -100.0, - ), - Arrow( - position: 00.0, - ), - Arrow( - position: 100.0, - ), - Arrow( - position: 200.0, - ), + ...notes.map((note) { + return Arrow( + position: _position != null + ? (note.time - _position!.inMilliseconds / 60000.0) * + 20 * + MediaQuery.of(context).size.height + : 0.0, + direction: note.direction, + ); + }), Positioned( top: 50, width: MediaQuery.of(context).size.width, @@ -171,15 +207,16 @@ class _LevelState extends State<Level> { class Arrow extends StatelessWidget { final double position; + final ArrowDirection direction; - const Arrow({super.key, required this.position}); + const Arrow({super.key, required this.position, required this.direction}); @override Widget build(BuildContext context) { return Positioned( - left: MediaQuery.of(context).size.width / 2 - 25, // Center the arrow - top: position, - child: Icon(size: 100, Icons.arrow_forward), + left: MediaQuery.of(context).size.width / 2 - 50, // Center the arrow + bottom: position + 50, + child: Icon(size: 100, color: Colors.redAccent.shade400, direction.icon), ); } } |