summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrangerot <purple@orangerot.dev>2024-12-29 16:25:32 +0100
committerOrangerot <purple@orangerot.dev>2024-12-29 16:25:32 +0100
commit5a763a5de26981c7d015a9e6276017b0f6c12f67 (patch)
tree5bfabf44be006101add9473c39a6ea13cc133ad2
parente9ba842e21503c00686e468729ad1f57ae96241b (diff)
style: refactored arrows in own file
-rw-r--r--lib/arrows.dart57
-rw-r--r--lib/level.dart238
2 files changed, 192 insertions, 103 deletions
diff --git a/lib/arrows.dart b/lib/arrows.dart
new file mode 100644
index 0000000..b4779f7
--- /dev/null
+++ b/lib/arrows.dart
@@ -0,0 +1,57 @@
+import 'package:flutter/material.dart';
+
+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;
+ double position = 0;
+ bool wasHit = false;
+
+ Note({required this.time, required this.direction});
+}
+
+class Arrows extends StatelessWidget {
+ final List<Note> notes;
+ final double position;
+
+ const Arrows({super.key, required this.notes, required this.position});
+
+ @override
+ Widget build(BuildContext context) {
+ return Stack(
+ children: notes.map((note) {
+ double position = note.position * 10000; // * 20 * MediaQuery.of(context).size.height;
+
+ return Arrow(
+ position: position,
+ direction: note.direction,
+ );
+ }).toList());
+ }
+}
+
+class Arrow extends StatelessWidget {
+ final double position;
+ final ArrowDirection direction;
+
+ const Arrow({super.key, required this.position, required this.direction});
+
+ @override
+ Widget build(BuildContext context) {
+ return Positioned(
+ left: MediaQuery.of(context).size.width / 2 - 50, // Center the arrow
+ bottom: position + 50,
+ child: Icon(size: 100, color: Colors.redAccent.shade400, direction.icon),
+ );
+ }
+}
diff --git a/lib/level.dart b/lib/level.dart
index 01083e2..548a752 100644
--- a/lib/level.dart
+++ b/lib/level.dart
@@ -3,6 +3,8 @@ 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 {
@@ -13,22 +15,11 @@ 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 InputDirection {
+ bool up = false;
+ bool down = false;
+ bool left = false;
+ bool right = false;
}
class _LevelState extends State<Level> {
@@ -41,6 +32,9 @@ class _LevelState extends State<Level> {
StreamSubscription? _durationSubscription;
StreamSubscription? _positionSubscription;
+ final FocusNode _focusNode = FocusNode();
+ InputDirection inputDirection = InputDirection();
+
List<Note> notes = [];
@override
@@ -82,6 +76,38 @@ 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 && 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('This is a toast message'),
+ duration: Duration(seconds: 2),
+ ),
+ );
+ }
+ }
+ }
});
String simfilePath = Directory(widget.stepmaniaFolderPath)
@@ -108,12 +134,12 @@ class _LevelState extends State<Level> {
if (arrowIndex < 0 || arrowIndex > 3) {
continue;
}
+ double beat =
+ measureIndex * 4.0 + (noteIndex.toDouble() / measure.length) * 4.0;
+ double minutesPerBeat = 1.0 / bpm;
+ double offsetMinutes = simfile!.offset / 60.0;
notes.add(Note(
- time: (measureIndex * 4.0 +
- (noteIndex.toDouble() / measure.length) * 4.0) *
- 1.0 /
- bpm +
- simfile!.offset / 60.0,
+ time: beat * minutesPerBeat + offsetMinutes,
direction: ArrowDirection.values[arrowIndex]));
}
}
@@ -125,75 +151,97 @@ class _LevelState extends State<Level> {
@override
Widget build(BuildContext context) {
- 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: [
- ...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,
- left: 0,
- child: Text(
- "Great!",
- textScaler: TextScaler.linear(4),
- textAlign: TextAlign.center,
+ 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
@@ -204,19 +252,3 @@ class _LevelState extends State<Level> {
super.dispose();
}
}
-
-class Arrow extends StatelessWidget {
- final double position;
- final ArrowDirection direction;
-
- const Arrow({super.key, required this.position, required this.direction});
-
- @override
- Widget build(BuildContext context) {
- return Positioned(
- left: MediaQuery.of(context).size.width / 2 - 50, // Center the arrow
- bottom: position + 50,
- child: Icon(size: 100, color: Colors.redAccent.shade400, direction.icon),
- );
- }
-}