抽牌游戏是一个简单但有趣的纸牌游戏。这篇文章我们来实现一个抽牌游戏,包括牌组管理、抽牌功能、洗牌功能、以及牌的网格展示。通过这个功能,我们能展示如何构建一个简单的交互式游戏 。

页面的基本结构
DrawCardsScreen是抽牌游戏的主页面:
dart
class DrawCardsScreen extends StatefulWidget {
const DrawCardsScreen({super.key});
@override
State<DrawCardsScreen> createState() => _DrawCardsScreenState();
}
class _DrawCardsScreenState extends State<DrawCardsScreen> {
final DeckOfCardsApi _api = DeckOfCardsApi();
String? _deckId;
List<dynamic> _drawnCards = [];
int _remaining = 52;
bool _isLoading = false;
_deckId存储牌组ID。
_drawnCards存储已抽取的牌。
_remaining记录剩余的牌数。
创建新牌组
_newDeck方法创建新牌组:
dart
Future<void> _newDeck() async {
setState(() => _isLoading = true);
try {
final data = await _api.getNewDeck();
setState(() {
_deckId = data['deck_id'];
_remaining = data['remaining'] ?? 52;
_drawnCards = [];
_isLoading = false;
});
} catch (e) {
setState(() => _isLoading = false);
}
}
调用API创建新牌组。
重置已抽取的牌和剩余牌数。
抽牌功能
_drawCards方法抽取指定数量的牌:
dart
Future<void> _drawCards(int count) async {
if (_deckId == null || _remaining < count) return;
setState(() => _isLoading = true);
try {
final data = await _api.drawCards(_deckId!, count: count);
setState(() {
_drawnCards = data['cards'] ?? [];
_remaining = data['remaining'] ?? 0;
_isLoading = false;
});
} catch (e) {
setState(() => _isLoading = false);
}
}
调用API抽取指定数量的牌。
更新已抽取的牌和剩余牌数。
洗牌功能
_shuffle方法重新洗牌:
dart
Future<void> _shuffle() async {
if (_deckId == null) return;
setState(() => _isLoading = true);
try {
final data = await _api.reshuffleDeck(_deckId!);
setState(() {
_remaining = data['remaining'] ?? 52;
_drawnCards = [];
_isLoading = false;
});
} catch (e) {
setState(() => _isLoading = false);
}
}
调用API重新洗牌。
重置已抽取的牌。
页面UI
页面显示牌组状态、操作按钮和已抽取的牌:
dart
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('抽牌游戏')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
const Icon(Icons.style, size: 40, color: Colors.blue),
const SizedBox(height: 8),
Text(_deckId != null ? '牌组已创建' : '未创建牌组', style: const TextStyle(fontWeight: FontWeight.w500)),
],
),
Column(
children: [
Text('$_remaining', style: Theme.of(context).textTheme.headlineMedium?.copyWith(fontWeight: FontWeight.bold)),
const Text('剩余牌数', style: TextStyle(color: Colors.grey)),
],
),
],
),
显示牌组状态和剩余牌数。
操作按钮
操作按钮包括创建新牌组、洗牌和抽牌:
dart
const SizedBox(height: 20),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _isLoading ? null : _newDeck,
icon: const Icon(Icons.add),
label: const Text('新牌组'),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton.icon(
onPressed: _deckId == null || _isLoading ? null : _shuffle,
icon: const Icon(Icons.shuffle),
label: const Text('洗牌'),
),
),
],
),
创建新牌组和洗牌按钮。
抽牌按钮:
dart
const SizedBox(height: 16),
Row(
children: [
Expanded(child: _buildDrawButton(1)),
const SizedBox(width: 8),
Expanded(child: _buildDrawButton(3)),
const SizedBox(width: 8),
Expanded(child: _buildDrawButton(5)),
],
),
提供抽1张、3张、5张的快捷按钮。
_buildDrawButton方法创建抽牌按钮:
dart
Widget _buildDrawButton(int count) {
return OutlinedButton(
onPressed: _deckId == null || _remaining < count || _isLoading ? null : () => _drawCards(count),
child: Text('抽$count张'),
);
}
如果牌组不存在或剩余牌数不足就禁用按钮。
已抽取的牌展示
已抽取的牌用GridView展示:
dart
const SizedBox(height: 24),
if (_isLoading)
const Expanded(child: LoadingWidget())
else if (_drawnCards.isEmpty)
const Expanded(child: Center(child: Text('点击上方按钮抽牌', style: TextStyle(color: Colors.grey))))
else
Expanded(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 0.7,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: _drawnCards.length,
itemBuilder: (context, index) {
final card = _drawnCards[index];
return Card(
clipBehavior: Clip.antiAlias,
child: AppNetworkImage(
imageUrl: card['image'] ?? '',
fit: BoxFit.contain,
borderRadius: BorderRadius.zero,
),
);
},
),
),
用GridView展示已抽取的牌。
每行3列,宽高比为0.7。
总结
这篇文章我们实现了一个抽牌游戏。涉及到的知识点包括:
- API集成 - 使用Deck of Cards API管理牌组
- 状态管理 - 管理牌组状态和已抽取的牌
- 网格布局 - 使用GridView展示牌
- 按钮设计 - 创建快捷操作按钮
- 网络图片加载 - 从API加载牌的图片
- 用户反馈 - 显示牌组状态和剩余牌数
抽牌游戏虽然功能简单,但通过清晰的UI设计和流畅的交互 ,能为用户提供一个有趣的游戏体验。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net