summaryrefslogtreecommitdiff
path: root/lib/level.dart
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2024-12-28 23:41:36 +0100
committerOrangerot <purple@orangerot.dev>2024-12-28 23:41:36 +0100
commite9ba842e21503c00686e468729ad1f57ae96241b (patch)
treebf61626ba13f3ae0950daf018d443a264abc3e0c /lib/level.dart
parent9eb8a2938271ad9855f3d72cbbf10eb9ba607cf1 (diff)
feat: display beats as arrows with correct time offset
Diffstat (limited to 'lib/level.dart')
-rw-r--r--lib/level.dart71
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),
);
}
}