MoodCanvas/lib/providers/drag_puzzle_provider.dart
fengshengxiong 91b7eebbf2 接入TopON
2026-01-22 16:34:55 +08:00

249 lines
6.1 KiB
Dart

import 'dart:async';
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:aesthetica_wallpaper/models/drag_puzzle_game.dart';
class DragPuzzleProvider extends ChangeNotifier {
DragPuzzleGame? _currentGame;
Timer? _timer;
DragPuzzleGame? get currentGame => _currentGame;
/// 创建拖拽式拼图游戏
Future<void> createDragPuzzle({
required String imagePath,
required DragPuzzleDifficulty difficulty,
}) async {
// 停止之前的计时器
_timer?.cancel();
// 分割图片
final pieces = await _splitImageForDrag(
imagePath,
difficulty.rows,
difficulty.cols,
);
// 打乱拼图块顺序
pieces.shuffle();
// 创建游戏
_currentGame = DragPuzzleGame(
pieces: pieces,
gridRows: difficulty.rows,
gridCols: difficulty.cols,
imagePath: imagePath,
);
// 开始计时
_startTimer();
notifyListeners();
}
/// 分割图片为拖拽式拼图块
Future<List<DragPuzzlePiece>> _splitImageForDrag(
String imagePath,
int rows,
int cols,
) async {
final pieces = <DragPuzzlePiece>[];
// 加载图片
final ByteData data = await rootBundle.load(imagePath);
final codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
final frame = await codec.getNextFrame();
final image = frame.image;
final pieceWidth = image.width ~/ cols;
final pieceHeight = image.height ~/ rows;
// 分割图片
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
final id = row * cols + col;
// 创建图片块
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
canvas.drawImageRect(
image,
Rect.fromLTWH(
col * pieceWidth.toDouble(),
row * pieceHeight.toDouble(),
pieceWidth.toDouble(),
pieceHeight.toDouble(),
),
Rect.fromLTWH(0, 0, pieceWidth.toDouble(), pieceHeight.toDouble()),
Paint(),
);
final picture = recorder.endRecording();
final pieceImage = await picture.toImage(pieceWidth, pieceHeight);
// 将图片转换为字节数据
final byteData = await pieceImage.toByteData(
format: ui.ImageByteFormat.png,
);
final uint8List = byteData!.buffer.asUint8List();
pieces.add(
DragPuzzlePiece(
id: id,
correctRow: row,
correctCol: col,
image: MemoryImage(uint8List),
),
);
}
}
return pieces;
}
/// 将拼图块放置到指定位置
void placePiece(int pieceId, int targetRow, int targetCol) {
if (_currentGame == null || _currentGame!.isComplete) return;
final pieces = List<DragPuzzlePiece>.from(_currentGame!.pieces);
final pieceIndex = pieces.indexWhere((p) => p.id == pieceId);
if (pieceIndex == -1) return;
final piece = pieces[pieceIndex];
// 检查目标位置是否已被占用
final existingPiece = _currentGame!.getPieceAt(targetRow, targetCol);
if (existingPiece != null) {
// 如果目标位置有其他块,将其移回底部
final existingIndex = pieces.indexWhere((p) => p.id == existingPiece.id);
pieces[existingIndex] = existingPiece.copyWith(
isPlaced: false,
currentRow: null,
currentCol: null,
);
}
// 放置当前块
pieces[pieceIndex] = piece.copyWith(
isPlaced: true,
currentRow: targetRow,
currentCol: targetCol,
);
// 增加移动次数
final newMoves = _currentGame!.moves + 1;
// 更新游戏状态
_currentGame = _currentGame!.copyWith(pieces: pieces, moves: newMoves);
// 检查是否完成
if (_currentGame!.checkComplete()) {
_completeGame();
}
notifyListeners();
}
/// 将拼图块移回底部
void removePiece(int pieceId) {
if (_currentGame == null || _currentGame!.isComplete) return;
final pieces = List<DragPuzzlePiece>.from(_currentGame!.pieces);
final pieceIndex = pieces.indexWhere((p) => p.id == pieceId);
if (pieceIndex == -1) return;
final piece = pieces[pieceIndex];
// 只有已放置的块才能移除
if (!piece.isPlaced) return;
pieces[pieceIndex] = piece.copyWith(
isPlaced: false,
currentRow: null,
currentCol: null,
);
_currentGame = _currentGame!.copyWith(
pieces: pieces,
moves: _currentGame!.moves + 1,
);
notifyListeners();
}
/// 开始计时
void _startTimer() {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (_currentGame != null && !_currentGame!.isComplete) {
_currentGame = _currentGame!.copyWith(
elapsedTime: _currentGame!.elapsedTime + const Duration(seconds: 1),
);
notifyListeners();
}
});
}
/// 完成游戏
void _completeGame() {
_timer?.cancel();
_currentGame = _currentGame!.copyWith(isComplete: true);
}
/// 重新开始游戏
void restartGame() {
if (_currentGame == null) return;
_timer?.cancel();
// 重置所有拼图块
final pieces = _currentGame!.pieces
.map(
(piece) => piece.copyWith(
isPlaced: false,
currentRow: null,
currentCol: null,
),
)
.toList();
// 重新打乱
pieces.shuffle();
_currentGame = _currentGame!.copyWith(
pieces: pieces,
elapsedTime: Duration.zero,
moves: 0,
isComplete: false,
);
_startTimer();
notifyListeners();
}
/// 提示功能
void showHint() {
if (_currentGame == null || _currentGame!.isComplete) return;
// 找到第一个未正确放置的块
final unplacedPieces = _currentGame!.unplacedPieces;
if (unplacedPieces.isNotEmpty) {
final hintPiece = unplacedPieces.first;
print(
'提示:将块 ${hintPiece.id} 放到位置 (${hintPiece.correctRow}, ${hintPiece.correctCol})',
);
}
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
}