summaryrefslogtreecommitdiff
path: root/lib/level.dart
diff options
context:
space:
mode:
Diffstat (limited to 'lib/level.dart')
-rw-r--r--lib/level.dart257
1 files changed, 171 insertions, 86 deletions
diff --git a/lib/level.dart b/lib/level.dart
index 1391f8a..aa042f4 100644
--- a/lib/level.dart
+++ b/lib/level.dart
@@ -3,6 +3,9 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:audioplayers/audioplayers.dart';
+import 'package:flutter/services.dart';
+import 'package:sense_the_rhythm/arrows.dart';
+import 'package:sense_the_rhythm/simfile.dart';
class Level extends StatefulWidget {
const Level({super.key, required this.stepmaniaFolderPath});
@@ -12,8 +15,16 @@ class Level extends StatefulWidget {
State<Level> createState() => _LevelState();
}
+class InputDirection {
+ bool up = false;
+ bool down = false;
+ bool left = false;
+ bool right = false;
+}
+
class _LevelState extends State<Level> {
final player = AudioPlayer();
+ Simfile? simfile;
bool _isPlaying = true;
Duration? _duration;
Duration? _position;
@@ -21,6 +32,11 @@ class _LevelState extends State<Level> {
StreamSubscription? _durationSubscription;
StreamSubscription? _positionSubscription;
+ final FocusNode _focusNode = FocusNode();
+ InputDirection inputDirection = InputDirection();
+
+ List<Note> notes = [];
+
@override
void setState(VoidCallback fn) {
// Subscriptions only can be closed asynchronously,
@@ -51,10 +67,7 @@ class _LevelState extends State<Level> {
_positionSubscription = player.onPositionChanged.listen(
(p) => setState(() => _position = p),
);
- }
- @override
- Widget build(BuildContext context) {
player.onDurationChanged.listen((Duration d) {
// print('Max duration: $d');
setState(() => _duration = d);
@@ -63,85 +76,172 @@ class _LevelState extends State<Level> {
player.onPositionChanged.listen((Duration p) {
// print('Current position: $p');
setState(() => _position = p);
+ for (final note in notes) {
+ note.position = note.time - p.inMilliseconds / 60000.0;
+ if (note.wasHit != null) {
+ continue;
+ }
+ if (note.position.abs() < 0.5 * 1.0 / 60.0) {
+ bool keypressCorrect = false;
+ switch (note.direction) {
+ case ArrowDirection.up:
+ keypressCorrect = inputDirection.up;
+ break;
+ case ArrowDirection.down:
+ keypressCorrect = inputDirection.down;
+ break;
+ case ArrowDirection.right:
+ keypressCorrect = inputDirection.right;
+ break;
+ case ArrowDirection.left:
+ keypressCorrect = inputDirection.left;
+ break;
+ }
+ if (keypressCorrect) {
+ print("you hit!");
+ note.wasHit = true;
+
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text('Great!'),
+ duration: Duration(milliseconds: 500),
+ ),
+ );
+ }
+ } else if (note.position < -0.5 * 1.0 / 60.0) {
+ print("Missed");
+ note.wasHit = false;
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text('Missed!'),
+ duration: Duration(milliseconds: 500),
+ ),
+ );
+ }
+ }
});
+ String simfilePath = Directory(widget.stepmaniaFolderPath)
+ .listSync()
+ .firstWhere((entity) => entity.path.endsWith('.sm'),
+ orElse: () => File(''))
+ .path;
+
String audioPath = Directory(widget.stepmaniaFolderPath)
.listSync()
.firstWhere((entity) => entity.path.endsWith('.ogg'),
orElse: () => File(''))
.path;
+
+ simfile = Simfile(simfilePath);
+ simfile!.load();
+
+ simfile!.chartSimplest!.beats.forEach((time, noteData) {
+ int arrowIndex = noteData.indexOf('1');
+ if (arrowIndex < 0 || arrowIndex > 3) {
+ return;
+ }
+ notes.add(Note(time: time, direction: ArrowDirection.values[arrowIndex]));
+ });
+
+ print(audioPath);
+
player.play(DeviceFileSource(audioPath));
- return Scaffold(
- appBar: AppBar(
- leading: IconButton(
- icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
- onPressed: () {
- if (_isPlaying) {
- player.pause();
- setState(() {
- _isPlaying = false;
- });
- } else {
- player.resume();
- setState(() {
- _isPlaying = true;
- });
- }
- },
- ),
- title: Text(widget.stepmaniaFolderPath.split('/').last),
- actions: [
- IconButton(
- icon: Icon(Icons.close),
- onPressed: () => Navigator.pop(context))
- ],
- bottom: PreferredSize(
- preferredSize: Size(double.infinity, 1.0),
- child: LinearProgressIndicator(
- value: (_duration != null &&
- _position != null &&
- _position!.inMilliseconds > 0 &&
- _position!.inMilliseconds < _duration!.inMilliseconds)
- ? _position!.inMilliseconds / _duration!.inMilliseconds
- : 0.0,
- )),
- ),
- body: Stack(children: [
- Arrow(
- position: -100.0,
- ),
- Arrow(
- position: 00.0,
- ),
- Arrow(
- position: 100.0,
- ),
- Arrow(
- position: 200.0,
- ),
- Positioned(
- top: 50,
- width: MediaQuery.of(context).size.width,
- left: 0,
- child: Text(
- "Great!",
- textScaler: TextScaler.linear(4),
- textAlign: TextAlign.center,
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return KeyboardListener(
+ focusNode: _focusNode,
+ autofocus: true,
+ onKeyEvent: (event) {
+ bool isDown = false;
+ if (event is KeyDownEvent) {
+ isDown = true;
+ } else if (event is KeyUpEvent) {
+ isDown = false;
+ } else {
+ return;
+ }
+ switch (event.logicalKey) {
+ case LogicalKeyboardKey.arrowUp:
+ inputDirection.up = isDown;
+ break;
+ case LogicalKeyboardKey.arrowDown:
+ inputDirection.down = isDown;
+ break;
+ case LogicalKeyboardKey.arrowLeft:
+ inputDirection.left = isDown;
+ break;
+ case LogicalKeyboardKey.arrowRight:
+ inputDirection.right = isDown;
+ break;
+ }
+ },
+ child: Scaffold(
+ appBar: AppBar(
+ leading: IconButton(
+ icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow),
+ onPressed: () {
+ if (_isPlaying) {
+ player.pause();
+ setState(() {
+ _isPlaying = false;
+ });
+ } else {
+ player.resume();
+ setState(() {
+ _isPlaying = true;
+ });
+ }
+ },
),
+ title: Text(widget.stepmaniaFolderPath.split('/').last),
+ actions: [
+ IconButton(
+ icon: Icon(Icons.close),
+ onPressed: () => Navigator.pop(context))
+ ],
+ bottom: PreferredSize(
+ preferredSize: Size(double.infinity, 1.0),
+ child: LinearProgressIndicator(
+ value: (_duration != null &&
+ _position != null &&
+ _position!.inMilliseconds > 0 &&
+ _position!.inMilliseconds < _duration!.inMilliseconds)
+ ? _position!.inMilliseconds / _duration!.inMilliseconds
+ : 0.0,
+ )),
),
- Positioned(
- left: MediaQuery.of(context).size.width / 2 - 50,
- bottom: 50,
- child: Container(
- width: 100,
- height: 100,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- // color: Colors.blue,
- border: Border.all(color: Colors.black, width: 10)),
+ body: Stack(children: [
+ Arrows(
+ notes: notes,
+ position: _position != null
+ ? _position!.inMilliseconds.toDouble()
+ : 0.0),
+ Positioned(
+ top: 50,
+ width: MediaQuery.of(context).size.width,
+ left: 0,
+ child: Text(
+ "Great!",
+ textScaler: TextScaler.linear(4),
+ textAlign: TextAlign.center,
+ ),
),
- ),
- ]));
+ Positioned(
+ left: MediaQuery.of(context).size.width / 2 - 50,
+ bottom: 50,
+ child: Container(
+ width: 100,
+ height: 100,
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ border: Border.all(color: Colors.black, width: 10)),
+ ),
+ ),
+ ])),
+ );
}
@override
@@ -152,18 +252,3 @@ class _LevelState extends State<Level> {
super.dispose();
}
}
-
-class Arrow extends StatelessWidget {
- final double position;
-
- const Arrow({super.key, required this.position});
-
- @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),
- );
- }
-}