본문 바로가기
Flutter for Beginners

Flutter 디지털 시계에 주사위 굴리기 추가

by Andrew's Akashic Records 2025. 4. 3.
728x90

가속도 센서 패키지 설치

sensors_plus 패키지란?

sensors_plus는 Flutter 앱에서 기기의 센서(가속도계, 자이로스코프, 자기장 등) 데이터를 쉽게 사용할 수 있도록 도와주는 인기 있는 플러그인입니다.다.

주요 센서 기능

센서 설명
accelerometerEventStream() 가속도계: 기기의 x, y, z축 방향 가속도 측정 (기기 흔들기 감지 등)
gyroscopeEventStream() 자이로스코프: 회전 속도 측정 (게임/AR 앱에서 방향 추적)
userAccelerometerEventStream() 중력 제외한 사용자 가속도 측정
magnetometerEventStream() 자기장 측정 (디지털 나침반 구현 시 사용)

 

예시: 가속도 스트림 사용

import 'package:sensors_plus/sensors_plus.dart';

void listenToAccelerometer() {
  accelerometerEventStream().listen((AccelerometerEvent event) {
    print('x: ${event.x}, y: ${event.y}, z: ${event.z}');
  });
}
  • event.x, event.y, event.z는 각 축의 가속도를 의미 (단위: m/s²)
  • 흔들기 감지나 기울임 감지에 주로 사용

예시: 기기 흔들기 감지 → 가속도계 사용

double delta = (event.x - previousX).abs();
if (delta > threshold) { /* 흔들림 감지 */ }

 

예시: 디지털 나침반 → 자기장 센서 사용

magnetometerEventStream().listen((event) {
  // 방향 각도 계산 가능
});

 

예시: 자이로 기반 게임 컨트롤러 → 자이로스코프 사용

gyroscopeEventStream().listen((event) {
  // 회전 방향 처리
});

디바이스별 지원유형

센서 유형 Android iOS 데스크탑
가속도계 O O X X
자이로스코프 O O X X
자기장 O O X X

 

 

설치 방법

dependencies:
  sensors_plus: ^6.1.1  # 가속도 센서용

or 

 $ flutter pub add sensors_plus

 

pubspec.yaml에 주사위 이미지 등록

flutter:
  assets:
    - assets/dice_1.png
    - assets/dice_2.png
    - assets/dice_3.png
    - assets/dice_4.png
    - assets/dice_5.png
    - assets/dice_6.png

 

dice_1.png
0.01MB
dice_2.png
0.01MB
dice_3.png
0.01MB
dice_4.png
0.02MB
dice_5.png
0.02MB
dice_6.png
0.02MB

작성코드

/screen/ DigitalClockScreen.dart

            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              ... 생략
              ElevatedButton(
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (_) => const DiceShakeScreen()),
                  );
                },
                child: const Text('🎲 주사위'),
              ),

            ],

주사위 링크

/screen/DiceShakeScreen.dart

import 'dart:math';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:sensors_plus/sensors_plus.dart';

// 주사위 흔들기 기능을 제공하는 StatefulWidget
class DiceShakeScreen extends StatefulWidget {
  const DiceShakeScreen({super.key});

  @override
  State<DiceShakeScreen> createState() => _DiceShakeScreenState();
}

class _DiceShakeScreenState extends State<DiceShakeScreen> {
  int _diceNumber = 1; // 현재 주사위 숫자 (1~6)
  double _lastX = 0;   // 직전 X축 가속도 값 (흔들림 감지용)
  final _random = Random(); // 랜덤 숫자 생성을 위한 객체
  double _sensitivity = 12; // 흔들림 민감도 (낮을수록 민감하게 반응)
  bool _isRolling = false; // 주사위 애니메이션 중 여부 표시

  @override
  void initState() {
    super.initState();

    // 센서 이벤트 스트림 구독 시작 (기기를 흔드는 동작 감지)
    accelerometerEventStream().listen((event) {
      double deltaX = (event.x - _lastX).abs(); // X축의 변화량 계산

      // 변화량이 민감도보다 크고 애니메이션 중이 아니라면 주사위 굴림
      if (deltaX > _sensitivity && !_isRolling) {
        _rollDiceWithAnimation();
      }

      _lastX = event.x; // 다음 비교를 위해 현재 값을 저장
    });
  }

  // 주사위를 굴리는 애니메이션 함수
  void _rollDiceWithAnimation() {
    int counter = 0; // 애니메이션 반복 횟수 카운터
    const totalTicks = 12; // 총 애니메이션 프레임 수
    const interval = Duration(milliseconds: 70); // 프레임 간 시간 간격

    // 애니메이션 시작 상태로 설정
    setState(() {
      _isRolling = true;
    });

    // 일정 주기로 주사위 숫자를 랜덤하게 바꾸며 애니메이션 효과 구현
    Timer.periodic(interval, (timer) {
      setState(() {
        _diceNumber = _random.nextInt(6) + 1; // 1~6 사이 랜덤 값 설정
      });

      counter++;
      if (counter >= totalTicks) {
        timer.cancel(); // 애니메이션 종료
        setState(() {
          _isRolling = false; // 종료 상태로 복귀
        });
      }
    });
  }

  // UI 빌드
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('주사위 흔들기')),
      body: Column(
        children: [
          // 주사위 이미지 및 안내 문구 영역
          Expanded(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // 현재 주사위 숫자에 해당하는 이미지 표시
                Image.asset('assets/dice_$_diceNumber.png', width: 150),
                const SizedBox(height: 20),
                // 애니메이션 중이 아닐 때만 안내 문구 표시
                if (!_isRolling)
                  const Text(
                    '기기를 흔들어 주사위를 굴리세요!',
                    style: TextStyle(fontSize: 18),
                  ),
              ],
            ),
          ),
          // 민감도 조절 슬라이더 UI (하단 고정)
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Text('민감도 조절', style: TextStyle(fontSize: 16)),
                // 슬라이더로 민감도 조절 (5~25 범위)
                Slider(
                  value: _sensitivity,
                  min: 5,
                  max: 25,
                  divisions: 20,
                  label: _sensitivity.toStringAsFixed(1),
                  onChanged: (value) {
                    setState(() {
                      _sensitivity = value; // 변경된 민감도 적용
                    });
                  },
                ),
                // 현재 설정된 민감도 표시
                Text('현재 민감도: ${_sensitivity.toStringAsFixed(1)}')
              ],
            ),
          ),
        ],
      ),
    );
  }
}

주사위 흔들기

 

728x90