Skip to content

Commit

Permalink
feat(dpad): allow Dpad buttons in two directions simultaneously (#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcowindt authored Apr 30, 2023
1 parent 542d10e commit ffc88cb
Show file tree
Hide file tree
Showing 10 changed files with 252 additions and 70 deletions.
13 changes: 7 additions & 6 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ PODS:
- Flutter
- network_info_plus (0.0.1):
- Flutter
- shared_preferences_ios (0.0.1):
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS

DEPENDENCIES:
- Flutter (from `Flutter`)
- motion_sensors (from `.symlinks/plugins/motion_sensors/ios`)
- network_info_plus (from `.symlinks/plugins/network_info_plus/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)

EXTERNAL SOURCES:
Flutter:
Expand All @@ -20,15 +21,15 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/motion_sensors/ios"
network_info_plus:
:path: ".symlinks/plugins/network_info_plus/ios"
shared_preferences_ios:
:path: ".symlinks/plugins/shared_preferences_ios/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/ios"

SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
motion_sensors: 03f55b7c637a7e365a0b5f9697a449f9059d5d91
network_info_plus: b78876159360f5580608c2cea620d6ceffabd0ad
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472

PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3

COCOAPODS: 1.11.2
COCOAPODS: 1.12.0
5 changes: 5 additions & 0 deletions lib/devices/device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ class Device {
this.state[this.keyMap[btnType]] = state;
}

void setStates(Map<String, int> btnTypeStates) {
this.state.addAll(
btnTypeStates.map((key, value) => MapEntry(this.keyMap[key], value)));
}

Device(GyroSettings gyroSettings, AccSettings accSettings,
DeviceSettings deviceSettings, SendPort stream) {
this.gyroSettings = gyroSettings;
Expand Down
6 changes: 6 additions & 0 deletions lib/server/events/multi_button_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class MultiButtonEvent {
final int slot;
final Map<String, int> value;

MultiButtonEvent(this.slot, this.value);
}
5 changes: 5 additions & 0 deletions lib/server/server_isolate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:wiimote_dsu/server/events/acc_event.dart';
import 'package:wiimote_dsu/server/events/button_event.dart';
import 'package:wiimote_dsu/server/events/change_slot_event.dart';
import 'package:wiimote_dsu/server/events/gyro_event.dart';
import 'package:wiimote_dsu/server/events/multi_button_event.dart';

class ServerIsolate {
static Future<SendPort> init() async {
Expand Down Expand Up @@ -47,6 +48,10 @@ class ServerIsolate {
server.slots[data.slot]?.setGyro(data);
} else if (data is AccEvent) {
server.slots[data.slot]?.setAcc(data);
} else if (data is MultiButtonEvent) {
server.slots[data.slot]?.setStates(data.value);
debugPrint(
'${DateTime.now().millisecondsSinceEpoch} [main->isolate] value: ${data.value}');
} else if (data is ButtonEvent) {
server.slots[data.slot]?.setState(data.btnType, data.value);
debugPrint(
Expand Down
175 changes: 175 additions & 0 deletions lib/ui/buttons/multi_dpad.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import 'package:flutter/material.dart';
import 'dart:math' as math;

import 'package:flutter/services.dart';

enum Direction {
up,
right,
down,
left,
}

class DPad extends StatefulWidget {
final double size;
final Function onUpdate;

const DPad({Key key, @required this.size, @required this.onUpdate})
: super(key: key);

@override
_DPadState createState() => _DPadState();
}

class _DPadState extends State<DPad> {
Set<Direction> _pressedDirections = {};
double get _radius => widget.size / 2;

final List<Set<Direction>> sectors = [
{Direction.up},
{Direction.up, Direction.right},
{Direction.right},
{Direction.right, Direction.down},
{Direction.down},
{Direction.down, Direction.left},
{Direction.left},
{Direction.left, Direction.up},
];

@override
Widget build(BuildContext context) {
return SizedBox(
width: widget.size,
height: widget.size,
child: Listener(
onPointerDown: _onPointerUpdate,
onPointerMove: _onPointerUpdate,
onPointerUp: _onPointerUp,
child: Container(
width: widget.size,
height: widget.size,
clipBehavior: Clip.none,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(_radius),
color: Colors.grey.shade100,
),
child: Stack(
children: [
Positioned(
top: 10,
left: _radius - _radius / 4,
child: Container(
decoration: BoxDecoration(
color: _pressedDirections.contains(Direction.up)
? Colors.black26
: Colors.white,
borderRadius: BorderRadius.circular(10.0)),
width: _radius / 2,
height: _radius - 24.0,
child: Icon(
Icons.arrow_upward,
size: 24.0,
color: _pressedDirections.contains(Direction.up)
? Colors.blue
: Colors.blueGrey,
))),
Positioned(
top: _radius - _radius / 4,
left: 10,
child: Container(
decoration: BoxDecoration(
color: _pressedDirections.contains(Direction.left)
? Colors.black26
: Colors.white,
borderRadius: BorderRadius.circular(10.0)),
width: _radius - 24.0,
height: _radius / 2,
child: Icon(
Icons.arrow_back,
size: 24.0,
color: _pressedDirections.contains(Direction.left)
? Colors.blue
: Colors.blueGrey,
))),
Positioned(
top: _radius - _radius / 4,
right: 10,
child: Container(
decoration: BoxDecoration(
color: _pressedDirections.contains(Direction.right)
? Colors.black26
: Colors.white,
borderRadius: BorderRadius.circular(10.0)),
width: _radius - 24.0,
height: _radius / 2,
child: Icon(
Icons.arrow_forward,
size: 24.0,
color: _pressedDirections.contains(Direction.right)
? Colors.blue
: Colors.blueGrey,
)),
),
Positioned(
bottom: 10,
left: _radius - _radius / 4,
child: Container(
decoration: BoxDecoration(
color: _pressedDirections.contains(Direction.down)
? Colors.black26
: Colors.white,
borderRadius: BorderRadius.circular(10.0)),
width: _radius / 2,
height: _radius - 24.0,
child: Icon(
Icons.arrow_downward,
size: 24.0,
color: _pressedDirections.contains(Direction.down)
? Colors.blue
: Colors.blueGrey,
)))
],
),
),
),
);
}

void _onPointerUp(PointerEvent event) {
setState(() {
_pressedDirections.clear();
widget.onUpdate(_pressedDirections);
});
}

void _onPointerUpdate(PointerEvent event) {
setState(() {
_updatePressedDirections(event.localPosition);
});
}

void _updatePressedDirections(Offset position) {
final double dx = position.dx - _radius;
final double dy = -position.dy + _radius;

if (Offset(dx, dy).distance < _radius / 3) {
// Middle dead zone
_pressedDirections.clear();
widget.onUpdate(_pressedDirections);
return;
}

final double angle = math.atan2(dx, dy) % (2 * math.pi);
final double degrees = angle * 180 / math.pi;
final int sector = ((degrees + 22.5) ~/ 45) % 8;

final newDirections = Set<Direction>.from(sectors[sector]);

if (_pressedDirections.length != newDirections.length ||
_pressedDirections.difference(newDirections).length > 0) {
HapticFeedback.mediumImpact();
_pressedDirections = newDirections;
widget.onUpdate(_pressedDirections);
}
}
}
85 changes: 39 additions & 46 deletions lib/ui/dpad.dart
Original file line number Diff line number Diff line change
@@ -1,55 +1,48 @@
import 'dart:isolate';

import 'package:flutter/material.dart';
import 'package:wiimote_dsu/ui/buttons/dpad_arrow.dart';
import 'package:provider/provider.dart';
import 'package:wiimote_dsu/models/device_settings.dart';
import 'package:wiimote_dsu/server/events/multi_button_event.dart';
import 'package:wiimote_dsu/ui/buttons/multi_dpad.dart';

class Dpad extends StatelessWidget {
final double width;
final double height;
final double size;

Dpad({this.size = 120.0});

static const DSUButtons = {
Direction.up: "D_UP",
Direction.right: "D_RIGHT",
Direction.down: "D_DOWN",
Direction.left: "D_LEFT"
};

Dpad({this.width = 1.0 * 180.0, this.height = 1.0 * 180.0});
static const offState = {
"D_UP": 0x00,
"D_RIGHT": 0x00,
"D_DOWN": 0x00,
"D_LEFT": 0x00,
};

@override
Widget build(BuildContext context) {
return Container(
width: width,
height: height,
child: Stack(children: <Widget>[
Positioned(
left: width * 0.5 - 0.125 * width,
top: 0,
child: DpadArrow(
Icons.arrow_upward,
btnType: "D_UP",
width: 0.25 * width,
height: 0.4 * height,
),
),
Positioned(
left: 0,
top: height * 0.5 - 0.125 * height,
child: DpadArrow(
Icons.arrow_back,
btnType: "D_LEFT",
width: 0.4 * width,
height: 0.25 * height,
)),
Positioned(
right: 0,
top: height * 0.5 - 0.125 * height,
child: DpadArrow(
Icons.arrow_forward,
btnType: "D_RIGHT",
width: 0.4 * width,
height: 0.25 * height,
)),
Positioned(
bottom: 0,
left: width * 0.5 - 0.125 * width,
child: DpadArrow(
Icons.arrow_downward,
btnType: "D_DOWN",
width: 0.25 * width,
height: 0.4 * height,
)),
]));
return Consumer<DeviceSettings>(
builder: (BuildContext context, DeviceSettings settings, Widget child) {
return DPad(
size: size,
onUpdate: (Set<Direction> directionsPressed) {
final mappedDirections =
directionsPressed.map((direction) => DSUButtons[direction]);
context.read<SendPort>().send(MultiButtonEvent(settings.slot,
offState.map((dArrow, state) {
if (mappedDirections.contains(dArrow)) {
return MapEntry(dArrow, 0xFF);
} else {
return MapEntry(dArrow, 0x00);
}
})));
});
});
}
}
3 changes: 1 addition & 2 deletions lib/ui/layouts/only_dpad_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class OnlyDpadLayout extends StatelessWidget implements DeviceLayout {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Dpad(
width: screenSize.height * 0.25,
height: screenSize.height * 0.25,
size: screenSize.height * 0.25,
),
],
));
Expand Down
3 changes: 1 addition & 2 deletions lib/ui/layouts/wii_classic_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ class WiiClassicLayout extends StatelessWidget implements DeviceLayout {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Dpad(
width: 120,
height: 120,
size: 120,
),
SizedBox(
width: 85,
Expand Down
3 changes: 1 addition & 2 deletions lib/ui/layouts/wii_mote_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ class WiiMoteLayout extends StatelessWidget implements DeviceLayout {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Dpad(
width: screenSize.height * 0.25,
height: screenSize.height * 0.25,
size: screenSize.height * 0.25,
),
SizedBox(
height: screenSize.height * 0.2 / 3,
Expand Down
Loading

0 comments on commit ffc88cb

Please sign in to comment.