贪吃蛇小游戏。
?
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: '贪吃蛇'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
//球的位置
Offset _ball = Offset.zero;
//每个快宽度固定的
const double _size = 20;
//贪吃蛇的位置
List<Offset> _snakeList = [Offset(_size * 2, 0), Offset(_size * 3, 0)];
//贪吃蛇的方向
enum Direction { Up, Down, Left, Right }
enum GameStatus { Over, Start }
Direction _direction = Direction.Up;
GameStatus _gameStatus = GameStatus.Start;
late Timer _timer;
class _MyHomePageState extends State<MyHomePage> {
//每次build之前被调用
@override
void didChangeDependencies() {
reSetGame();
super.didChangeDependencies();
}
void reSetGame() {
var period = Duration(milliseconds: 200);
double maxWidth = MediaQuery.of(context).size.width;
double maxHeight = MediaQuery.of(context).size.height;
double widthPad = maxWidth % _size;
double heightPad = maxHeight % _size;
maxWidth = maxWidth - widthPad;
maxHeight -= heightPad;
_ball = randomPosition(maxWidth, maxHeight);
_timer = Timer.periodic(period, (timer) {
//更新蛇的位置
List<Offset> newSnakeList = List.generate(_snakeList.length, (index) {
if (index > 0) {
return _snakeList[index - 1];
} else {
final snakeHead = _snakeList[0];
switch (_direction) {
case Direction.Up:
return Offset(
snakeHead.dx, (snakeHead.dy - _size + maxHeight) % maxHeight);
case Direction.Down:
return Offset(snakeHead.dx, (snakeHead.dy + _size) % maxHeight);
case Direction.Left:
return Offset(
(snakeHead.dx - _size + maxWidth) % maxWidth, snakeHead.dy);
case Direction.Right:
return Offset((snakeHead.dx + _size) % maxWidth, snakeHead.dy);
}
}
});
//贪吃蛇吃到块
if (newSnakeList[0] == _ball) {
//吧贪吃蛇加一个
newSnakeList..add(_snakeList[_snakeList.length - 1]);
setState(() {
_ball = randomPosition(maxWidth, maxHeight);
});
}
//贪吃蛇迟到自己
List<Offset> judgeSnakeList = List.from(newSnakeList);
judgeSnakeList.removeAt(0);
if (judgeSnakeList.contains(newSnakeList[0])) {
setState(() {
_gameStatus = GameStatus.Over;
_timer.cancel();
});
}
setState(() {
_snakeList = newSnakeList;
});
});
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
body: RawKeyboardListener(
focusNode: FocusNode(),
autofocus: true,
onKey: (event) {
if (event.runtimeType == RawKeyDownEvent) {
Direction newDirection = Direction.Left;
switch (event.logicalKey.keyLabel) {
case "Arrow Up":
// 处理对立面
if (_direction == Direction.Down) {
return;
}
newDirection = Direction.Up;
break;
case "Arrow Down":
// 处理对立面
if (_direction == Direction.Up) {
return;
}
newDirection = Direction.Down;
break;
case "Arrow Left":
// 处理对立面
if (_direction == Direction.Right) {
return;
}
newDirection = Direction.Left;
break;
case "Arrow Right":
// 处理对立面
if (_direction == Direction.Left) {
return;
}
newDirection = Direction.Right;
break;
}
setState(() {
_direction = newDirection;
});
}
},
child: _gameStatus == GameStatus.Start
? _buildGameStart()
: _buildGameOver(),
)
// This trailing comma makes auto-formatting nicer for build methods.
);
}
GestureDetector _buildGameOver() {
return GestureDetector(
onTap: () {},
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
child: Text("点击继续游戏(假装有广告其实没有)"),
onPressed: () {
setState(() {
_gameStatus = GameStatus.Start;
reSetGame();
});
},
),
TextButton(
child: Text("点击重新游戏(假装有广告其实没有)"),
onPressed: () {
setState(() {
_gameStatus = GameStatus.Start;
_direction = Direction.Up;
_snakeList = [Offset(_size * 2, 0), Offset(_size * 3, 0)];
reSetGame();
});
},
)
],
),
),
);
}
_buildGameStart() {
return Stack(
children: _snakeList
.map((snake) => Positioned.fromRect(
rect: Rect.fromCenter(
center: adjust(snake), width: _size, height: _size),
child: Container(
margin: EdgeInsets.all(1),
color: Colors.black,
)))
.toList()
//蛇
..add(Positioned.fromRect(
rect: Rect.fromCenter(
center: adjust(_ball), width: _size, height: _size),
child: Container(
margin: EdgeInsets.all(1),
color: Colors.orange,
))),
);
}
Offset adjust(Offset offset) {
return Offset(offset.dx + (_size / 2), offset.dy + (_size / 2));
}
Offset randomPosition(double widthRange, double heightRange) {
var rng = Random();
int intWidthRange = widthRange.toInt();
int intHeightRange = heightRange.toInt();
int finalWdith = rng.nextInt(intWidthRange);
int finalHeight = rng.nextInt(intHeightRange);
double widthPad = finalWdith % _size;
double heightPad = finalHeight % _size;
double actualWidth = finalWdith - widthPad;
double actualHeight = finalHeight - heightPad;
return Offset(actualWidth, actualHeight);
}
}
|