Flutter棋类游戏控制插件chessnutdriver的使用

Flutter棋类游戏控制插件chessnutdriver的使用

chessnutdriver 是一个用于在 Flutter 应用程序中快速连接 chessnut-board 的插件。它允许开发者通过蓝牙与棋盘进行通信,并接收其事件。

截图

截图

开始使用 chessnutdriver

添加依赖

pubspec.yaml 文件中添加以下依赖:

dependencies:
  chessnutdriver: ^0.0.1

然后运行 flutter pub get 来获取依赖。

导入包

在 Dart 文件中导入 chessnutdriver 包:

import 'package:chessnutdriver/chessnutdriver.dart';

连接到棋盘并监听事件

以下是一个完整的示例代码,展示了如何连接到棋盘并通过蓝牙与其通信:

// 初始化蓝牙通信客户端
ChessnutCommunicationClient chessnutCommuniChessnutCommunicationClient = ChessnutCommunicationClient(
  ChessnutCommunicationType.bluetooth,
  (v) => flutterReactiveBle.writeCharacteristicWithResponse(write, value: v),
  waitForAck: ackEnabled
);

// 订阅蓝牙读取流 A 和 B
boardBtInputStreamA = flutterReactiveBle
    .subscribeToCharacteristic(readA)
    .listen((list) {
      chessnutCommuniChessnutCommunicationClient.handleReceive(Uint8List.fromList(list));
    });
boardBtInputStreamB = flutterReactiveBle
    .subscribeToCharacteristic(readB)
    .listen((list) {
      chessnutCommuniChessnutCommunicationClient.handleAckReceive(Uint8List.fromList(list));
    });

// 初始化棋盘
ChessnutBoard nBoard = new ChessnutBoard();
await nBoard.init(chessnutCommuniChessnutCommunicationClient);
print("chessnutBoard connected");

实际操作

为了快速了解如何使用该插件,可以在以下项目中查看其实现,该项目目前尚未开源。

https://khad.im/p/white-pawn

完整示例代码

以下是完整的示例代码,展示如何在 Flutter 中使用 chessnutdriver 插件:

import 'dart:async';
import 'dart:typed_data';

import 'package:chessnutdriver/chessnutdriver.dart';
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  final _ble = FlutterReactiveBle();
  final _scanner = BleScanner(ble: _ble, logMessage: print);
  runApp(
    MultiProvider(
      providers: [
        Provider.value(value: _scanner),
        StreamProvider<BleScannerState>(
          create: (_) => _scanner.state,
          initialData: const BleScannerState(
            discoveredDevices: [],
            scanIsInProgress: false,
          ),
        ),
      ],
      child: MaterialApp(
        title: 'Flutter example',
        home: MyApp(),
      ),
    ),
  );
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final flutterReactiveBle = FlutterReactiveBle();

  final bleReadCharacteristicA = Uuid.parse("1B7E8262-2877-41C3-B46E-CF057C562023");
  final bleReadCharacteristicB = Uuid.parse("1B7E8273-2877-41C3-B46E-CF057C562023");
  final bleWriteCharacteristic = Uuid.parse("1B7E8272-2877-41C3-B46E-CF057C562023");

  ChessnutBoard connectedBoard;
  StreamSubscription<ConnectionStateUpdate> boardBtStream;
  StreamSubscription<List<int>> boardBtInputStreamA;
  StreamSubscription<List<int>> boardBtInputStreamB;
  bool loading = false;
  bool ackEnabled = true;

  void connectBle() async {
    await Permission.bluetoothScan.request();
    await Permission.bluetoothConnect.request();

    String deviceId = await Navigator.of(context).push(MaterialPageRoute(builder: (context) => DeviceListScreen()));

    setState(() {
      loading = true;
    });

    boardBtStream = flutterReactiveBle.connectToDevice(
      id: deviceId,
      connectionTimeout: const Duration(seconds: 5),
    ).listen((e) async {
      if (e.connectionState == DeviceConnectionState.connected) {
        List<DiscoveredService> services = await flutterReactiveBle.discoverServices(e.deviceId);
        await flutterReactiveBle.requestMtu(deviceId: deviceId, mtu: 247); // Important: Increase MTU

        QualifiedCharacteristic readA;
        QualifiedCharacteristic readB;
        QualifiedCharacteristic write;
        for (var service in services) {
          for (var characteristicId in service.characteristicIds) {
            if (characteristicId == bleReadCharacteristicA) {
              readA = QualifiedCharacteristic(
                serviceId: service.serviceId,
                characteristicId: bleReadCharacteristicA,
                deviceId: e.deviceId
              );
            }

            if (characteristicId == bleReadCharacteristicB) {
              readB = QualifiedCharacteristic(
                serviceId: service.serviceId,
                characteristicId: bleReadCharacteristicB,
                deviceId: e.deviceId
              );
            }

            if (characteristicId == bleWriteCharacteristic) {
              write = QualifiedCharacteristic(
                serviceId: service.serviceId,
                characteristicId: bleWriteCharacteristic,
                deviceId: e.deviceId
              );
            }
          }
        }

        ChessnutCommunicationClient chessnutCommuniChessnutCommunicationClient = ChessnutCommunicationClient(
          ChessnutCommunicationType.bluetooth,
          (v) => flutterReactiveBle.writeCharacteristicWithResponse(write, value: v),
          waitForAck: ackEnabled
        );
        boardBtInputStreamA = flutterReactiveBle
            .subscribeToCharacteristic(readA)
            .listen((list) {
              chessnutCommuniChessnutCommunicationClient.handleReceive(Uint8List.fromList(list));
            });
        boardBtInputStreamB = flutterReactiveBle
            .subscribeToCharacteristic(readB)
            .listen((list) {
              chessnutCommuniChessnutCommunicationClient.handleAckReceive(Uint8List.fromList(list));
            });
          

        // connect to board and initialize
        ChessnutBoard nBoard = new ChessnutBoard();
        await nBoard.init(chessnutCommuniChessnutCommunicationClient);
        print("chessnutBoard connected");

        // set connected board
        setState(() {
          connectedBoard = nBoard;
          loading = false;
        });
      }
    });
  }

  Map<String, String> lastData;

  LEDPattern ledpattern = LEDPattern();

  void toggleLed(String square) {
    ledpattern.setSquare(square, !ledpattern.getSquare(square));
    connectedBoard.setLEDs(ledpattern);
    setState(() {});
  }

  void disconnectBle() {
    boardBtInputStreamA.cancel();
    boardBtInputStreamB.cancel();
    boardBtStream.cancel();
    setState(() {
      boardBtInputStreamA = null;
      boardBtInputStreamB = null;
      boardBtStream = null;
      connectedBoard = null;
    });
  }

  void testLeds() async {
    LEDPattern pattern;
    for (var square in ChessnutProtocol.squares) {
      pattern = LEDPattern();
      pattern.setSquare(square, true);
      await connectedBoard.setLEDs(pattern);
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    double width = MediaQuery.of(context).size.width;
    return Scaffold(
      appBar: AppBar(
        title: Text("chessnutdriver example"),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Checkbox(value: ackEnabled, onChanged: connectedBoard == null ? (state) => setState(() => ackEnabled = state) : null),
              SizedBox(width: 4),
              Text("Enable Acks"),
            ],
          ),
          Center(child: TextButton(
            child: Text(connectedBoard == null ? "Try to connect to board (BLE)" : (boardBtStream != null ? "Disconnect" : "")),
            onPressed: !loading && connectedBoard == null ? connectBle : (boardBtStream != null && !loading ? disconnectBle : null),
          )),
          Center(child: TextButton(
            child: Text("Test LEDS"),
            onPressed: !loading && connectedBoard != null ? testLeds : null,
          )),
          Center(
            child: StreamBuilder(
              stream: connectedBoard?.getBoardUpdateStream(),
              builder: (context, AsyncSnapshot<Map<String, String>> snapshot) {
                if (!snapshot.hasData && lastData == null) return Text("- no data -");

                Map<String, String> fieldUpdate = snapshot.data ?? lastData;
                lastData = fieldUpdate;
                List<Widget> rows = [];
                
                for (var i = 0; i < 8; i++) {
                  List<Widget> cells = [];
                  for (var j = 0; j < 8; j++) {
                      MapEntry<String, String> entry = fieldUpdate.entries.toList()[i * 8 + j];
                      cells.add(
                        TextButton(
                          onPressed: () => toggleLed(entry.key),
                          style: TextButton.styleFrom(
                            padding: EdgeInsets.zero,
                            minimumSize: Size(width / 8 - 4, width / 8 - 4),
                            alignment: Alignment.centerLeft
                          ),
                          child: Container(
                            padding: EdgeInsets.only(bottom: 2),
                            width: width / 8 - 4,
                            height: width / 8 - 4,
                            child: DecoratedBox(
                              decoration: BoxDecoration(
                                borderRadius: BorderRadius.circular(2),
                                color: ledpattern.getSquare(entry.key) ? Colors.blueAccent : Colors.black54,
                              ),
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: [
                                  Text(entry.key, style: TextStyle(color: Colors.white)),
                                  Text(entry.value ?? ".", style: TextStyle(color: Colors.white, fontSize: 8)),
                                ],
                              )
                            ),
                          ),
                        )
                      );
                  }
                  rows.add(Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: cells,
                  ));
                }

                return Column(
                  children: rows,
                );
              }
            ),
          ),
        ],
      ),
    );
  }
}

更多关于Flutter棋类游戏控制插件chessnutdriver的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter棋类游戏控制插件chessnutdriver的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


chessnut_driver 是一个用于在 Flutter 应用中控制棋类游戏的插件,特别是针对 Chessnut 智能棋盘。它允许开发者通过蓝牙与 Chessnut 棋盘进行通信,获取棋子的移动信息并发送反馈。以下是如何使用 chessnut_driver 插件的基本步骤:

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 chessnut_driver 依赖:

dependencies:
  flutter:
    sdk: flutter
  chessnut_driver: ^1.0.0  # 请确保使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 初始化 ChessnutDriver

在你的 Flutter 应用中,首先需要初始化 ChessnutDriver

import 'package:chessnut_driver/chessnut_driver.dart';

ChessnutDriver chessnutDriver = ChessnutDriver();

3. 扫描并连接设备

使用 chessnutDriver 扫描附近的 Chessnut 设备并连接:

void scanAndConnect() async {
  // 扫描设备
  List<BluetoothDevice> devices = await chessnutDriver.scanDevices();

  // 假设我们选择第一个设备
  if (devices.isNotEmpty) {
    BluetoothDevice device = devices.first;

    // 连接设备
    bool isConnected = await chessnutDriver.connect(device);
    if (isConnected) {
      print("Connected to ${device.name}");
    } else {
      print("Failed to connect");
    }
  }
}

4. 监听棋子移动

连接成功后,你可以监听棋子的移动事件:

void listenToMoves() {
  chessnutDriver.onMove.listen((move) {
    print("Move detected: ${move.from} to ${move.to}");
    // 在这里处理移动逻辑,例如更新棋盘状态
  });
}

5. 发送反馈

你可以通过 chessnutDriver 向 Chessnut 棋盘发送反馈,例如点亮 LED 灯:

void sendFeedback() async {
  // 例如,点亮 A1 位置的 LED
  bool success = await chessnutDriver.sendFeedback('A1', LedColor.red);
  if (success) {
    print("Feedback sent successfully");
  } else {
    print("Failed to send feedback");
  }
}

6. 断开连接

当不再需要连接时,记得断开连接:

void disconnect() async {
  await chessnutDriver.disconnect();
  print("Disconnected");
}

7. 处理错误

在使用过程中,可能会遇到一些错误,例如连接失败或通信中断。你可以通过监听错误流来处理这些情况:

void handleErrors() {
  chessnutDriver.onError.listen((error) {
    print("Error occurred: $error");
    // 在这里处理错误逻辑
  });
}

8. 完整示例

以下是一个简单的完整示例,展示了如何扫描、连接、监听移动并发送反馈:

import 'package:flutter/material.dart';
import 'package:chessnut_driver/chessnut_driver.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ChessnutExample(),
    );
  }
}

class ChessnutExample extends StatefulWidget {
  [@override](/user/override)
  _ChessnutExampleState createState() => _ChessnutExampleState();
}

class _ChessnutExampleState extends State<ChessnutExample> {
  ChessnutDriver chessnutDriver = ChessnutDriver();

  [@override](/user/override)
  void initState() {
    super.initState();
    scanAndConnect();
    listenToMoves();
    handleErrors();
  }

  void scanAndConnect() async {
    List<BluetoothDevice> devices = await chessnutDriver.scanDevices();
    if (devices.isNotEmpty) {
      BluetoothDevice device = devices.first;
      bool isConnected = await chessnutDriver.connect(device);
      if (isConnected) {
        print("Connected to ${device.name}");
      } else {
        print("Failed to connect");
      }
    }
  }

  void listenToMoves() {
    chessnutDriver.onMove.listen((move) {
      print("Move detected: ${move.from} to ${move.to}");
      // 在这里处理移动逻辑
    });
  }

  void sendFeedback() async {
    bool success = await chessnutDriver.sendFeedback('A1', LedColor.red);
    if (success) {
      print("Feedback sent successfully");
    } else {
      print("Failed to send feedback");
    }
  }

  void handleErrors() {
    chessnutDriver.onError.listen((error) {
      print("Error occurred: $error");
      // 在这里处理错误逻辑
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Chessnut Example"),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: sendFeedback,
          child: Text("Send Feedback"),
        ),
      ),
    );
  }
}
回到顶部