Help us understand the problem. What is going on with this article?

【Flutter】Flutter製アプリをリリースしてみた、あとARとかも使ってみた話

アプリ概要

ゴルフのオリンピックゲームの計算やボールとピンまでの距離のAR測定,1−18までの乱数を生成することができる、ゴルフ幹事向けのアプリです。

App Store はこちら
Google Play Store はこちら

image.png

ファイル名ファイル名ファイル名

使用した技術

  • bloc
  • Provider
  • rxDart
  • Admob
  • Firebase Analytics
  • ARKit(iOSのみ)

ソースコードはこちら

https://github.com/Tetsukick/enGolf

AR技術のご紹介

iPhoneのみARKitを活用したプラグイン(arkit_flutter)が公開されていたので、そちらを活用して、タップした2点間の距離を測れるアプリを作成いたしました。

AR距離測定画面のソースコードを記載しておきます。
Sampleを80%ぐらい流用して簡単に開発できました。

import 'package:arkit_plugin/arkit_plugin.dart';
import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

import 'dart:io';

class ARMeasureScreen extends StatefulWidget {
  @override
  _ARMeasureScreen createState() => _ARMeasureScreen();
}

class _ARMeasureScreen extends State<ARMeasureScreen> {
  ARKitController arkitController;
  vector.Vector3 lastPosition;

  @override
  void dispose() {
    arkitController?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context){
    return Platform.isIOS ? Scaffold(
      body: Container(
        child: ARKitSceneView(
          enableTapRecognizer: true,
          onARKitViewCreated: onARKitViewCreated,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.delete),
        backgroundColor: Colors.lightGreen,
        onPressed: () {
          arkitController.remove('point');
          arkitController.remove('text');
          arkitController.remove('line');
          lastPosition = null;
        },
      ),
    ) :
    Scaffold(
      body: Center(
        child: Text('Androidには対応しておりません\n現在開発中のためしばらくお待ち下さい。'),
      ),
    );
  }

  void onARKitViewCreated(ARKitController arkitController) {
    this.arkitController = arkitController;
    this.arkitController.onARTap = (ar) {
      final point = ar.firstWhere(
            (o) => o.type == ARKitHitTestResultType.featurePoint,
        orElse: () => null,
      );
      if (point != null) {
        _onARTapHandler(point);
      }
    };
  }

  void _onARTapHandler(ARKitTestResult point) {
    final position = vector.Vector3(
      point.worldTransform.getColumn(3).x,
      point.worldTransform.getColumn(3).y,
      point.worldTransform.getColumn(3).z,
    );
    final material = ARKitMaterial(
        lightingModelName: ARKitLightingModel.constant,
        diffuse: ARKitMaterialProperty(color: Colors.blue));
    final sphere = ARKitSphere(
      radius: 0.006,
      materials: [material],
    );
    final node = ARKitNode(
      name: 'point',
      geometry: sphere,
      position: position,
    );
    arkitController.add(node);

    if (lastPosition != null) {
      final line = ARKitLine(
        fromVector: lastPosition,
        toVector: position,
      );
      final lineNode = ARKitNode(
          name: 'line',
          geometry: line
      );
      arkitController.add(lineNode);

      final distance = _calculateDistanceBetweenPoints(position, lastPosition);
      final point = _getMiddleVector(position, lastPosition);
      _drawText(distance, point);
    }
    lastPosition = position;
  }

  String _calculateDistanceBetweenPoints(vector.Vector3 A, vector.Vector3 B) {
    final length = A.distanceTo(B);
    return '${(length * 100).toStringAsFixed(2)} cm';
  }

  vector.Vector3 _getMiddleVector(vector.Vector3 A, vector.Vector3 B) {
    return vector.Vector3((A.x + B.x) / 2, (A.y + B.y) / 2, (A.z + B.z) / 2);
  }

  void _drawText(String text, vector.Vector3 point) {
    final textGeometry = ARKitText(
      text: text,
      extrusionDepth: 1,
      materials: [
        ARKitMaterial(
          diffuse: ARKitMaterialProperty(color: Colors.red),
        )
      ],
    );
    const scale = 0.001;
    final vectorScale = vector.Vector3(scale, scale, scale);
    final node = ARKitNode(
      name: 'text',
      geometry: textGeometry,
      position: point,
      scale: vectorScale,
    );
    arkitController.add(node);
  }
}

tetsukick
2017新卒iOSエンジニア 2019/10 よりインドネシア駐在 使命は、ある世界での当たり前のなにかを作ること。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした