diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/arrows.dart | 57 | ||||
| -rw-r--r-- | lib/level.dart | 238 | 
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), -    ); -  } -} | 
