LoginSignup
14
17

Flutterを使ってキャラ操作アプリを作った話

Last updated at Posted at 2023-06-24

背景

スマホを使ってロボットを簡単に操作できたらいいなぁ と思いついたのですが,
AndroidとかiPhoneとかいろいろ対応するの大変そうだなぁ と探していたところ,こちらのツールを発見

要はAndroidでもiOSでもmacOSでもWindowsでも動くようなアプリを一度に作れてしまうというツヨツヨなツールです
今回はこれを使ってVirtual Joystickでキャラクターを操作するアプリを作ってみました!

なおこちらの記事は,Flutterに関する基礎的な知識を有した方向けです!
環境構築やFlutterの使い方に関しては,公式の記事チュートリアルをご確認ください!

環境

  • OS: Windows 11
  • Flutter:
    $ flutter --version
    Flutter 3.10.5 • channel stable • https://github.com/flutter/flutter.git
    Framework • revision 796c8ef792 (11 days ago) • 2023-06-13 15:51:02 -0700
    Engine • revision 45f6e00911
    Tools • Dart 3.0.5 • DevTools 2.23.1
    
  • Andoroid Studio: Flamingo | 2022.2.1
  • Java: java17 for Windows
  • Visual Studio Code いわずと知れたエディタ Flutterの拡張機能がかなり充実いていてとても使いやすいです!
  • Application: for Windows 今回はWindows用のアプリを作る手順で説明していきます!

プロジェクト作成

まずはVSCodeを開き新しいFlutterプロジェクトを作成します.
Ctrl+Shift+Pでコマンドパレットを開き,Flutterと検索するとNew Projectの欄が出てきます.
image.png

これが出ない方はVSCodeのFlutter環境構築ができていないので,以下の記事を参考に環境を作ってみてください!
https://docs.flutter.dev/get-started/editor

次にApplicationを選択し,
image.png
アプリケーションを作成するフォルダパスを指定します.
image.png
最後にアプリケーションの名前を設定すると,
image.png

このような形でプロジェクトが自動生成されます とても便利で最初はかなり驚きました!
image.png

アプリ設定

こちらのサイトで使った設定ファイルをほとんどそのまま用います.
プロジェクトフォルダ直下の,pubspec.yamlanalysis_options.yamlを以下のように編集します.

pubspec.yaml
name: vitrual_controller
description: A new Flutter project.

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 0.0.1+1

environment:
  sdk: '>=2.19.4 <4.0.0'

dependencies:
  flutter:
    sdk: flutter

  english_words: ^4.0.0
  provider: ^6.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_lints: ^2.0.0

flutter:
  uses-material-design: true
analysis_options.yaml
include: package:flutter_lints/flutter.yaml

linter:
  rules:
    prefer_const_constructors: false
    prefer_final_fields: false
    use_key_in_widget_constructors: false
    prefer_const_literals_to_create_immutables: false
    prefer_const_constructors_in_immutables: false
    avoid_print: false

Virtual Joystickパッケージのインストール

今回は以下のツールを用います.

まずはインストール
VSCodeでCtrl+@でターミナルを開き,以下を実行します

$ flutter pub add flutter_joystick

これでVirtualJoystickを用いてアプリケーションを作れるようになります.

アプリ実装

まずは実行

では実際にアプリを作ります!main.dartに以下のコードを張り付けてみてください!

main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_joystick/flutter_joystick.dart';
import 'dart:math';

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

class MyAppState extends ChangeNotifier {
}

const ballSize = 20.0;
const transition_step = 10.0;
const rotation_step = 0.1;

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyAppState(),
      child: MaterialApp(
        title: 'Virtual Controller App',
        theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(seedColor: Color.fromARGB(255, 13, 0, 255)),
        ),
        darkTheme: ThemeData.dark(),
        themeMode: ThemeMode.system, 
        home: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double _x = 500;
  double _y = 250;
  double _yaw = 0;

  JoystickMode _joystickMode = JoystickMode.all;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Align(
            alignment: const Alignment(-0.8, 0.8),
            child: Joystick(
              mode: _joystickMode,
              listener: (details) {
                setState(() {
                  _x = _x - transition_step * details.y * sin(_yaw) + transition_step * details.x * cos(_yaw);
                  _y = _y + transition_step * details.y * cos(_yaw) + transition_step * details.x * sin(_yaw);
                });
              },
            ),
          ),
          Align(
            alignment: const Alignment(0.8, 0.8),
            child: Joystick(
              mode: _joystickMode,
              listener: (details) {
                setState(() {
                  _yaw = _yaw +  rotation_step * details.x;
                });
              },
            ),
          ),
          Transform.translate(
            offset: Offset(_x, _y),
            child: Transform.rotate(
              angle: _yaw,
              child: Icon(
                Icons.flutter_dash,
                color: Theme.of(context).colorScheme.primary,
                size: 200,
              ),
            ),
          ),
        ],
      ),
    );
  }
}

いったん動かしてみます!
ビルドがWindowsになっているのを確認して,(自分が試したいデバイスで問題ないです!)
image.png
右上の再生ボタンを押します.
image.png

するとこんな感じのアプリが立ち上がります!
image.png
左でキャラクターの平行移動,右で回転が制御できます.実際に動かしてみてください!
動画だとこんな感じ

コード解説

ココからはコードの解説をしていきます! 基本的なところは飛ばして,JoyStickの配置やキャラクター動作の実装のあたりを中心に解説していきます!

まずは44~48行目でキャラクターの位置・姿勢,JoyStickのモードを初期化します.

main.dart
// lines 44-48
  double _x = 0;
  double _y = 500;
  double _yaw = 0;

  JoystickMode _joystickMode = JoystickMode.all;

画面配置とキャラ移動は51行目以降で実装されています

main.dart
// lines 51-
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Align(
            alignment: const Alignment(-0.8, 0.8),
            child: Joystick(
              mode: _joystickMode,
              listener: (details) {
                setState(() {
                  _x = _x - transition_step * details.y * sin(_yaw) + transition_step * details.x * cos(_yaw);
                  _y = _y + transition_step * details.y * cos(_yaw) + transition_step * details.x * sin(_yaw);
                });
              },
            ),
          ),
          Align(
            alignment: const Alignment(0.8, 0.8),
            child: Joystick(
              mode: _joystickMode,
              listener: (details) {
                setState(() {
                  _yaw = _yaw +  rotation_step * details.x;
                });
              },
            ),
          ),
          Transform.translate(
            offset: Offset(_x, _y),
            child: Transform.rotate(
              angle: _yaw,
              child: Icon(
                Icons.flutter_dash,
                color: Theme.of(context).colorScheme.primary,
                size: 200,
              ),
            ),
          ),
        ],
      ),
    );
  }

それぞれのボタンの役割とAPIを以下に示します

Joystickウィジェット内のlistenerパラメータ内で,setState()関数を用いてJoyStickの状態から位置と角度を更新します.この辺りはロボティクスにも通じそう.
位置の更新は以下

main.dart
// lines 60-63
                setState(() {
                  _x = _x - transition_step * details.y * sin(_yaw) + transition_step * details.x * cos(_yaw);
                  _y = _y + transition_step * details.y * cos(_yaw) + transition_step * details.x * sin(_yaw);
                });

yaw角の更新は以下

main.dart
// lines 72-74
                setState(() {
                  _yaw = _yaw +  rotation_step * details.x;
                });

更新された位置・姿勢が,Transformウィジェットのtranslaterotationメソッドを用いて,リアルタイムでキャラクターに設定されます.

main.dart
//lines 78-88
         Transform.translate(
            offset: Offset(_x, _y),
            child: Transform.rotate(
              angle: _yaw,
              child: Icon(
                Icons.flutter_dash,
                color: Theme.of(context).colorScheme.primary,
                size: 200,
              ),
            ),
          ),

今後の展望

これをロボットを動かすためのアプリケーションにしたい...。

余談

FlutterではGoogleさんが作ったDartという言語を使ってアプリケーションを作成します.
おそらく見慣れない方が多いはずです(私も完全に初心者です).ですが,ある程度Javaに理解があればその考え方を踏襲しているらしいのでなんとなくわかるみたいです.

ちなみに私の場合はJavaもわからないので初めは全くピンと来ていませんでした.しかし,DocumentやTutorial,VSCodeの拡張機能がかなりしっかりしていて,こんな私でも3日くらいで簡単にアプリを作れるようになるくらいにはなれました.おすすめです.

今回はこれで以上です! 最後まで読んでいただきありがとうございました!

14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17