Flutterでチンチロリン

公開:2020/10/01
更新:2020/10/03
14 min読了の目安(約12600字TECH技術記事

Flutterにて、チンチロリンを作ってみました。

とりあえず遊べればよいというものです。

  • 二人以上でゲームでき、おまけで、ダイス個数変更

チンチロリン実行」でブラウザ実行できます。

チンチロリン

import 'package:flutter/material.dart';
import 'dart:math' show Random;

// #########################################################################
// ##### Start:constants.dart#####
//   (強)
// アラシ : サイコロの出した数が3個とも一致したもの
// シゴロ : サイコロの目が(4, 5, 6)
// ロッポウ : 3つ中2つのサイコロがゾロ目、ゾロ目でないサイコロが6の目(例:5, 5, 6)
// ゴケ : 3つ中2つのサイコロがゾロ目、ゾロ目でないサイコロが5の目
// ヨツヤ : 3つ中2つのサイコロがゾロ目、ゾロ目でないサイコロが4の目
// サンタ : 3つ中2つのサイコロがゾロ目、ゾロ目でないサイコロが3の目
// ニゾウ : 3つ中2つのサイコロがゾロ目、ゾロ目でないサイコロが2の目
// ピン : 3つ中2つのサイコロがゾロ目、ゾロ目でないサイコロが1の目
// 目なし : 3つの目それぞれ値が違ったとき
// ヒフミ : サイコロの目が(1, 2, 3)
// (弱)
const Map kChinchiroResults = {
  111: 'ピンゾロアラシ',
  112: 'ニゾウ',
  113: 'サンタ',
  114: 'ヨツヤ',
  115: 'ゴケ',
  116: 'ロッポウ',
  122: 'ピン',
  123: 'ヒフミ',
  124: '目無し',
  125: '目無し',
  126: '目無し',
  133: 'ピン',
  134: '目無し',
  135: '目無し',
  136: '目無し',
  144: 'ピン',
  145: '目無し',
  146: '目無し',
  155: 'ピン',
  156: '目無し',
  166: 'ピン',
  222: 'アラシ',
  223: 'サンタ',
  224: 'ヨツヤ',
  225: 'ゴケ',
  226: 'ロッポウ',
  233: 'ニゾウ',
  234: '目無し',
  235: '目無し',
  236: '目無し',
  244: 'ニゾウ',
  245: '目無し',
  246: '目無し',
  255: 'ニゾウ',
  256: '目無し',
  266: 'ニゾウ',
  333: 'アラシ',
  334: 'ヨツヤ',
  335: 'ゴケ',
  336: 'ロッポウ',
  344: 'サンタ',
  345: '目無し',
  346: '目無し',
  355: 'サンタ',
  356: '目無し',
  366: 'サンタ',
  444: 'アラシ',
  445: 'ゴケ',
  446: 'ロッポウ',
  455: 'ヨツヤ',
  456: 'シゴロ',
  466: 'ヨツヤ',
  555: 'アラシ',
  556: 'ロッポウ',
  566: 'ゴケ',
  666: 'アラシ',
};
// ##### Finish:constants.dart#####
// #########################################################################

// #########################################################################
// ##### Start:main.dart#####
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        iconTheme: IconThemeData(
          size: 50,
        ),
      ),
      home: ChinchiroScreen(),
    );
  }
}
// ##### Finish:main.dart#####
// #########################################################################

// #########################################################################
// ##### Start:chinchiro_screen.dart#####
class ChinchiroScreen extends StatefulWidget {
  
  _ChinchiroScreenState createState() => _ChinchiroScreenState();
}

class _ChinchiroScreenState extends State<ChinchiroScreen> {
  final _chinchiroSets = <ChinchiroPlay>[];
  int _numberDices = 3;

  Widget _buildSetWidgets(List<Widget> dices) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemBuilder: (BuildContext context, int index) => dices[index],
      itemCount: dices.length,
    );
  }

  void _createSets() {
    setState(() {
      _chinchiroSets.add(ChinchiroPlay(numberDices: _numberDices));
    });
  }

  void _removeSets() {
    setState(() {
      if (_chinchiroSets.isNotEmpty) {
        _chinchiroSets.removeAt(_chinchiroSets.length - 1); //配列の最後尾を削除
      }
    });
  }

  void _changeNumberDices(int number) {
    setState(() {
      if ((_numberDices < 2) && number < 0) {
        return;
      }
      _numberDices += number;
    });
  }

  
  void initState() {
    super.initState();
    _createSets();
    _createSets();
  }

  
  Widget build(BuildContext context) {
    final gridView = Container(
      padding: EdgeInsets.symmetric(horizontal: 8.0),
      child: _buildSetWidgets(_chinchiroSets),
    );

    return Scaffold(
      appBar: AppBar(
        title: const Text('チンチロリン'),
      ),
      body: gridView,
      persistentFooterButtons: <Widget>[
        FittedBox(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              Text('人数:${_chinchiroSets.length}'),
              IconButton(
                icon: Icon(Icons.add),
                onPressed: _createSets,
              ),
              IconButton(
                icon: Icon(Icons.remove),
                onPressed: _removeSets,
              ),
              Text('ダイス個数:$_numberDices'),
              IconButton(
                icon: Icon(Icons.add),
                onPressed: () => _changeNumberDices(1),
              ),
              IconButton(
                icon: Icon(Icons.remove),
                onPressed: () => _changeNumberDices(-1),
              ),
            ],
          ),
        ),
      ],
    );
  }
}
// ##### Finish:chinchiro_screen.dart#####
// #########################################################################

// #########################################################################
// ##### Start:chinchiro_play.dart#####
//import 'package:flutter/material.dart';
class ChinchiroPlay extends StatefulWidget {
  ChinchiroPlay({Key key, this.numberDices = 1}) : super(key: key);

  final int numberDices;

  
  _ChinchiroPlayState createState() => _ChinchiroPlayState();
}

class _ChinchiroPlayState extends State<ChinchiroPlay>
    with TickerProviderStateMixin {
  // 0:dice = 0 = fake = motion
  var _diceIcons = <Widget>[
    Icon(Icons.help),
    Icon(
      Icons.looks_one,
      color: Colors.red,
      size: 50.0,
    ),
    Icon(Icons.looks_two),
    Icon(Icons.looks_3),
    Icon(Icons.looks_4),
    Icon(Icons.looks_5),
    Icon(Icons.looks_6),
  ];
  final _dices = <Icon>[];

  // For chinchiro
  List<int> _chinchiroResultList = [];
  int _chinchiroResultNumber;
  String _chinchiroResult = 'チンチロの結果';

  // アニメーションボタン参考:(https://medium.com/flutter-community/animated-send-button-in-flutter-94c1834268b1)
  // For Animation
  AnimationController _animationController;
  double _containerPaddingLeft;
  double _animationValue;
  double _translateX;
  double _translateY;
  double _rotate;
  double _scale;
  bool show;
  bool _diceRollNow;
  Color _color;

  
  void initState() {
    super.initState();
    _initDices();
    // For Animation
    _initAnimationValue();
    _initAnimation();
  }

  // For Animation
  void _initAnimationValue() {
    _containerPaddingLeft = 20.0;
    _translateX = 0;
    _translateY = 0;
    _rotate = 0;
    _scale = 1;
    _diceRollNow = false;
    _color = Colors.lightBlue;
  }

  // For Animation
  void _initAnimation() {
    _animationController = AnimationController(
        vsync: this, duration: Duration(milliseconds: 1300));
    show = true;
    _animationController.addListener(() {
      setState(() {
        show = false;
        _animationValue = _animationController.value;
        if (_animationValue >= 0.2 && _animationValue < 0.4) {
          _containerPaddingLeft = 100.0;
          _color = Colors.green;
        } else if (_animationValue >= 0.4 && _animationValue <= 0.5) {
          _translateX = 80.0;
          _rotate = -20.0;
          _scale = 0.1;
        } else if (_animationValue >= 0.5 && _animationValue <= 0.8) {
          _translateY = -20.0;
        } else if (_animationValue >= 0.81) {
          _containerPaddingLeft = 20.0;
          _diceRollNow = true;

          // Add
          //sleep(Duration(seconds: 1));
          _diceRollNow = false;
          _initAnimationValue();
          _initAnimation();
          // Dice Roll
          _diceRoll();
        }
      });
    });
  }

  void _initDices() {
    setState(() {
      for (var i = 0; i < widget.numberDices; i++) {
        _dices.add(_diceIcons[0]);
      }
    });
  }

  void _createDices() {
    setState(() {
      _chinchiroResultList = [];
      for (var i = 0; i < widget.numberDices; i++) {
        int dice = Random().nextInt(6) + 1;
        _dices.add(_diceIcons[dice]);
        _chinchiroResultList.add(dice);
      }
      _chinchiroResultList.sort();
    });
  }

  Widget _buildDiceWidgets(List<Widget> dices) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3,
      ),
      itemBuilder: (BuildContext context, int index) => dices[index],
      itemCount: dices.length,
    );
  }

  void _diceRoll() {
    setState(() {
      _dices.removeRange(0, _dices.length);
      _createDices();
      _chinchiroResultCheck();
    });
  }

  void _chinchiroResultCheck() {
    if (widget.numberDices == 3) {
      _chinchiroResultNumber = _chinchiroResultList[0] * 100 +
          _chinchiroResultList[1] * 10 +
          _chinchiroResultList[2];
      _chinchiroResult = kChinchiroResults[_chinchiroResultNumber];
    }
  }

  void _notifyDiceRoll() {
    // Vibration.vibrate(pattern: [50, 100, 50, 200]);
  }

  Widget diceRollButton() {
    return Padding(
      padding: EdgeInsets.all(0.0),
      child: Center(
        child: GestureDetector(
          onTap: () {
            _animationController.forward();
            _notifyDiceRoll();
          },
          child: AnimatedContainer(
            decoration: BoxDecoration(
              color: _color,
              borderRadius: BorderRadius.circular(100.0),
              boxShadow: [
                BoxShadow(
                  color: _color,
                  blurRadius: 21,
                  spreadRadius: -15,
                  offset: Offset(
                    0.0,
                    20.0,
                  ),
                )
              ],
            ),
            padding: EdgeInsets.only(
              left: _containerPaddingLeft,
              right: 20.0,
              top: 10.0,
              bottom: 10.0,
            ),
            duration: Duration(milliseconds: 400),
            curve: Curves.easeOutCubic,
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                (!_diceRollNow)
                    ? AnimatedContainer(
                        duration: Duration(milliseconds: 400),
                        child: Icon(Icons.send),
                        curve: Curves.fastOutSlowIn,
                        transform: Matrix4.translationValues(
                            _translateX, _translateY, 0)
                          ..rotateZ(_rotate)
                          ..scale(_scale),
                      )
                    : Container(),
                AnimatedSize(
                  vsync: this,
                  duration: Duration(milliseconds: 600),
                  child: show ? SizedBox(width: 10.0) : Container(),
                ),
                AnimatedSize(
                  vsync: this,
                  duration: Duration(milliseconds: 200),
                  child: show ? Text('Dice Roll') : Container(),
                ),
                AnimatedSize(
                  vsync: this,
                  duration: Duration(milliseconds: 200),
                  child: _diceRollNow ? Icon(Icons.done) : Container(),
                ),
                AnimatedSize(
                  vsync: this,
                  alignment: Alignment.topLeft,
                  duration: Duration(milliseconds: 600),
                  child: _diceRollNow ? SizedBox(width: 10.0) : Container(),
                ),
                AnimatedSize(
                  vsync: this,
                  duration: Duration(milliseconds: 200),
                  child: _diceRollNow ? Text('Done') : Container(),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  
  Widget build(BuildContext context) {
    var gridView = Container(
      padding: EdgeInsets.symmetric(horizontal: 8.0),
      child: _buildDiceWidgets(_dices),
    );

    return Scaffold(
      body: Center(
        child: Column(
          children: [
            Expanded(
              child: gridView,
            ),
            const SizedBox(height: 24.0),
            Text(widget.numberDices == 3 ? '$_chinchiroResult' : ''),
            diceRollButton(),
          ],
        ),
      ),
    );
  }
}
// ##### Finish:chinchiro_play.dart#####
// #########################################################################